width の外になぜはみ出すの?基本の基本の復習

先日ですね、PHP で吐き出される文字列が、改行させずに、なぜか width で指定した幅からはみ出してしまう・・・ということがあって。
どうしてだろう?どうしてだろう?PHP の方が間違っているのかと思い込んで、散々考えても分からなかったので、人に聞いてみたら、「CSS で普通に word-wrap: break-word とか word-break: break-all で制御すればいいだけなんじゃないの?」と言われ、言われてみればそうですね。一発で改行されました。思い込みって怖いなー。盲目になってしまった時は、人に聞くのが一番ですね・・・。

word-wrap: break-word と word-break: break-all については、また考察したいのですが、width を無視して要素がはみ出る場合について、ごく基本の基本に立ち返って、まとめてみたいと思います。

インラインの非置換要素

HTMLの要素は、インライン、インラインブロック、ブロックと3つのレベルに分けられます。
さらにインラインの要素は、width、height の指定できる置換要素、width、height の指定できない非置換要素があります。

インラインの置換要素(width、height を指定できる)

img iframe video embed audio canvas object

インラインの非置換要素(width、height を指定できない)

span ruby sub sup strong em mark b i small br u s ins del
cite q abbr dfn code kbd samp var bdo label

要するに、span 等のインラインレベルの非置換要素に、width を指定しても無視されます。

margin、border、padding を考慮せず、width:100% に指定

width:100% とは、content の幅です。左右の margin、border、padding の数値が「0」でなければ、その分、親要素の width からはみ出します。

回避策① calc()関数を使う

margin:0; border:2px; padding:2px の場合、左右のはみ出しの合計は 8px。calc()関数を使って、8px を引きます。
width: calc(100% – 8px)
「-」と「+」の演算子の前後にはスペースを入れるルールあり

回避策② 入れ子にする

外側の要素を width:100% でいっぱいに広げ、内側の要素の margin、border、padding、content(width:auto)を包むという考え方です。

回避策③ box-sizing プロパティの利用

box-sizing: border-box
と記述することで、要素に指定した width および height の中で border、padding を取るようにブラウザに指示。
margin は含まれない点に注意。

box-sizing を利用する際は、プレフィックスも記述した方がいいようです。
-webkit-box-sizing: border-box; /* Webkit */
-moz-box-sizing: border-box; /* Firefox */
box-sizing: border-box; /* 標準 */

width の幅を超える連続する英数字

日本語や、適度にスペースの入った英語等の文章は、width で指定された幅に合わせて、自動改行されますが、切れ目のはっきりとしない連続する英数字は、width の幅からはみ出して表示されます。長いURL など、そういう例ですね。
この場合は、word-wrap: break-word や word-break: break-all を使って制御を掛けるのですが、長くなりそうなので、それはまた次回、じっくりまとめたいと思います。

サイトにソースコードを記述する

このサイトのページに、CSSやPHPなどのソースコードを載せたいのですが、そのための記述の仕方をまとめます。

やりたいこと

左に行数を表示し、右にソースコードを記述

HTMLタグ

<pre>タグ: 整形済みテキストを表示する(ブロックレベル要素)
<code>タグ: プログラムコードやHTMLやCSSなどのコードを示す(インライン要素)

CSSカウンター

counter-reset プロパティ: カウンターに名前を設定し、値を初期化
counter-increment プロパティ: counter-resetで設定したカウンターの値に1を加算
content プロパティ: 要素を生成された値で置き換え
counter() 関数: 値を生成
::before 疑似要素: 選択した要素の最初の子要素として擬似要素を作成

ソースコード記述の為のCSS例

/* 全体を収めるブロック */
div.code-toolbar {
    position: relative;
}

/* 整数済み部分 */
pre {
    position: relative;
    padding: 1em 1em 1em 3.8em;
    overflow: auto;
    counter-reset: linenumber;
    border-left: 1px solid hsla(256, 97%, 27%, 0.71);
    font-size: 14px;
    box-shadow: 0 0.5px 0.5px rgba(0,0,0,0.1), 0 0.5px 0.5px rgba(0,0,0,0.1);
    border-top: .1px solid hsla(0, 0%, 84%, 0.1);
    border-right: .1px solid hsla(0, 0%, 84%, 0.1);
    background: #f5f2f0;
    display: block;
}

/* ソースコード記入部分 */
code {
    color: black;
    background: none;
    text-shadow: 0 1px white;
    font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
    text-align: left;
    white-space: pre;
    word-spacing: normal;
    word-break: normal;
    word-wrap: normal;
    line-height: 1.5;
    -moz-tab-size: 4;
    -o-tab-size: 4;
    tab-size: 4;
    -webkit-hyphens: none;
    -moz-hyphens: none;
    -ms-hyphens: none;
    hyphens: none;
    position: relative;
}

/* 行数表示部分全体 */
.line-numbers-rows {
    position: absolute;
    pointer-events: none;
    top: 0;
    font-size: 100%;
    left: -3.8em;
    width: 3em;
    letter-spacing: -1px;
    border-right: 1px solid #999;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* 各行数表示 */
.line-numbers-rows > span {
    pointer-events: none;
    display: block;
    counter-increment: linenumber;
}

/* カウンター */
.line-numbers-rows > span:before {
    content: counter(linenumber);
    color: #999;
    display: block;
    padding-right: 0.8em;
    text-align: right;
}

ソースコード記述の為のHTML例

<div class="code-toolbar">
<pre><code>/* シュークリームが大好きです */
<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

ブラウザでの表示

/* シュークリームが大好きです */