世界を動かす技術を、日本語で。

開発者への罠

2025年8月16日原文(qouteall.fun)

概要

  • 開発者が陥りやすい HTML/CSS、Unicode、浮動小数点、時間 に関する落とし穴の要約
  • 直感に反する挙動誤解 しやすい仕様を中心に整理
  • バグの原因 となりやすいポイントを明確化
  • 各分野ごと に代表的なトラップを箇条書きで説明
  • 対策や回避策も簡潔に記載

HTML・CSSの落とし穴

  • flexboxやgrid内 では、デフォルトで min-width: auto が設定され、内容に応じて最小幅が決まる
    • min-width: 0 を明示的に指定することで、flex-shrinkやoverflow等の他プロパティが正常に動作
  • width: autoheight: auto の挙動は異なる
    • 横方向は親要素の空間を埋めるが、縦方向は内容に合わせて伸びる
    • inline要素やinline-block要素、float要素 ではwidth: autoは拡張しない
  • margin: 0 auto は水平方向中央寄せ
    • margin: auto 0 は通常上下中央寄せにならない
    • flex-direction: column のflexboxでのみmargin: auto 0が垂直中央寄せとなる
  • マージンの折り畳み(margin collapse) は垂直方向のみ発生
    • BFC(Block Formatting Context)やborder/padding指定で回避可能
    • display: flow-rootoverflow: hidden 等でBFCを作成
  • 親がfloat子要素のみ含む場合、親の高さが0になる
    • BFCで解決可能
  • スタッキングコンテキスト の発生条件
    • transform, filter, opacity等の特殊効果
    • position: fixed/sticky、z-index指定+position: absolute/relative
    • isolation: isolate
  • z-indexはスタッキングコンテキストをまたいで効かない
    • position: absolute/fixedは最も近いpositioned ancestor基準
  • 100vh問題
    • モバイルブラウザのアドレスバー表示/非表示で高さが変動
    • 100dvh が推奨値
  • position: absolute は親要素ではなく最も近いpositioned ancestor基準
  • display: flexやgridの親下でfloatは無効
  • 親のwidth/height未定義時、%指定のwidth/heightは効かない
  • display: inline はwidth/heightやmargin-top/bottom無効
  • HTMLの空白・改行はデフォルトで1つの空白にまとめられる
    • <pre> で回避可能だが、先頭・末尾の空白は特殊挙動
    • inline-block要素間の空白 はスペースとして描画(flexboxやgridでは発生しない)
  • text-alignはインライン要素のみ整列
  • width/heightはデフォルトでpadding/borderを含まない
    • box-sizing: border-box で全体幅に含める
  • 画像の遅延読み込みによるCumulative Layout Shift
    • <img>にwidth/height属性指定 推奨
  • ファイルダウンロードリクエストはChrome DevToolsで見えない
    • chrome://net-export/ で確認

Unicode・テキスト処理の落とし穴

  • コードポイント(rune)とグラフェームクラスタ の違い
    • GUI上の「1文字」はグラフェームクラスタ
    • 絵文字は複数コードポイントから成ることも
  • UTF-8は1~4バイト、UTF-16は2バイト単位
    • 文字数・インデックスの扱いは言語ごとに異なる
  • Rust: UTF-8、s.len()はバイト数、s.chars().count()はコードポイント数
  • Go: 文字列はバイト列、インデックスもバイト単位
  • Java/C#/JS: UTF-16、長さ・インデックスは2バイト単位
  • Python: len(s)はコードポイント数、インデックスもコードポイント単位
  • C++: std::stringはエンコーディング非依存、バイト単位
  • グラフェームクラスタ単位の長さ・インデックス取得は標準で不可
  • BOM(Byte Order Mark) の扱い
    • 一部ソフトで非対応
  • バイナリ→文字列変換時の不正箇所はU+FFFD(�)に置換
  • 正規化・類似文字 問題
    • 例:éはU+00E9またはU+0065 U+0301
  • ゼロ幅・不可視文字 の混入
  • 改行コードの違い
    • Windows: CRLF (\r\n)、Linux/Mac: LF (\n)
  • 漢字統合(Han unification) によるフォント依存表示
    • 多言語対応ではフォント選択が重要

浮動小数点の落とし穴

  • NaNは何とも等しくない(NaN == NaNはfalse)
    • 計算にNaNが混入すると全体がNaN化
  • +Infと-InfはNaNと別物
  • -0.0と+0.0は区別される
    • 1.0 / +0.0は+Inf、1.0 / -0.0は-Inf
  • JSON標準はNaN/Inf非対応
    • JS: nullに変換
    • Python: allow_nan=Falseでエラー
    • Go: エラー
  • 浮動小数点の比較は誤差を考慮
    • abs(a - b) < 0.00001等で比較
  • JavaScriptの安全な整数範囲
    • 2^53-1までが安全、それ以上はBigInt推奨
    • 大きな整数をJSONで扱う場合は文字列化
  • 結合法則・分配法則が厳密には成立しない
    • 並列計算で非決定的結果になることも
  • 除算は乗算より遅い
    • 逆数を先に計算して乗算で高速化
  • ハードウェアによる差異
    • FMA(fused multiply-add)やサブノーマル数
    • 丸めモード(RNTE, RTZ等)、CPU/GPUでの挙動違い
    • X86の80bit FPUは非推奨
  • 精度向上の工夫
    • 計算グラフの浅さ、FMA活用、中間値の絶対値管理

時間処理の落とし穴

  • Unixタイムスタンプはうるう秒を考慮しない
    • うるう秒付近で「引き伸ばし」や「圧縮」が発生
  • タイムゾーン・DST(夏時間)の影響
    • タイムスタンプ保存+UIで人間可読化が推奨
    • サーバーはUTC設定が望ましい
    • 分散システムでタイムゾーン不一致は厄介
  • システム時刻とハードウェア時刻の違い
    • タイムゾーン変更時はDB再起動等が必要な場合あり
  • NTP同期等による時刻の「巻き戻り」
    • 時間の一意性・単調性に注意

上記以外にも、各分野で 直感に反する仕様や落とし穴 が多く存在。 実装前に仕様書や公式ドキュメントの確認 が重要。

Hackerたちの意見

これは役立つ情報やヒントがまとめられてていいね。誰かがこれから学べるといいけど。自分は、既に知ってることしか理解できなかった気がするし、知ってることにすごく近かっただけかも。それって、どんなトピックの教科書でも同じことが起こるよね。内容は整理されてて、既に知識がある人にはわかりやすいけど、何も知らない人には教えるのがすごく難しい。

どんなトピックの教科書でも同じことが起こるよね。内容は整理されてて、既に知識がある人にはわかりやすいけど それがマニュアルが存在する理由だと思う。記録を残しておくことで、記憶を頼らなくて済むから。これがほとんどのUnixマニュアルの役割だよね。ソフトウェアが何をできるかは知ってるけど、どうやって特定のことをやるかを思い出す必要がある。 > 何も知らない人には教えるのがすごく難しい。だから必要なのは、初心者向けのチュートリアル(学びたい人)か、ガイド(やりたいことをするための初心者/中級者向け)だね。この場合、マニュアルはより良い質問をするためだけに役立つ(今、自分が知らないことがわかるから)。

最近の罠:正規表現の意味は言語によって微妙に違うんだよね。例えば、Pythonでは a{,3} は0から3個の「a」文字にマッチするけど、JavaScriptではリテラル文字列の「a{,3}」にマッチする。

正規表現は実際の仕様というよりは技術に近いね。基礎的なメカニズムを説明している計算理論の入門書を読む時間を見つけるのが一番いいと思う。

自分はいつもregex101を使って正規表現を作成してる。いろんなエンジンに切り替えられるから便利だよ。

あと一歩でお気に入りのトラップって感じの[a-z]に名誉の言及。

CSSとC++は「サブセットを選んでそれを強制するか、さもなくば苦しむ」っていう性質があるよね。やることリストには、CSS属性がまだ存在しないプルリクエストをマージするには手動でオーバーライドが必要なGitHubアクションを作るって書いてある。

CSSがどう機能するのか、ちょっと不明だな。私の知識では、ほとんどのCSSプロパティは互換性がないと思う。もし強制されるサブセットが「すでに存在するCSSプロパティ」なら、開発者はそのプロパティが存在しない場合、どうすればいいの?デザインを変えるの?

ページの最初の「罠」には「min-width: autoはコンテンツによって最小幅が決まる」と書いてあるけど、フレックスやグリッド以外ではこれは間違いだよ。MDNによると、「ブロックボックス、インラインボックス、インラインブロック、すべてのテーブルレイアウトボックスでは、autoは0に解決される。」だって。 https://developer.mozilla.org/en-US/docs/Web/CSS/min-width

最初の罠は実際には「CSSプロパティは孤立して読むことはできない。名前が示すように、デフォルトや値がどのようにカスケードするかは、ドキュメントが使用するすべてのルールに影響を与える」ってことだと思う。

CSSのテキストプロパティのカスケードは、まあまあ理解できるけど、CSSのレイアウトはどの視点からも全然わからん。ページデザイナー、実装者、ユーザー、何でもいいけど、誰を想定してるのか全くわからん。

ありがとう、修正するよ。

Hacker Newsで議論の続きを見る