<img>のwidthとheight属性は、何を指定するものなのでしょう?
現在の <img> のwidthとheightについてまとめてみました。
HTML4.01のドラフトを確認すると、
width = length [CN]
Image and object width override.
height = length [CN]
Image and object height override.
When specified, the width and height attributes tell user agents to override the natural image or object size in favor of these values.
When the object is an image, it is scaled.指定されたとき、widthとheight属性は、これらの値を優先して自然な画像やオブジェクトのサイズを上書きするようにユーザエージェントに指示します。
オブジェクトが画像の場合、それは拡大縮小されます。
ということで、上書きする形で表示サイズを変更するのにも使われていました。ドラフトには、%で指定可能なことも書かれています。
しかし、現在のLiving Standardの<img>の解説をMDNで確認すると、
height
The intrinsic height of the image, in pixels. Must be an integer without a unit.
画像固有の高さをピクセル単位で指定します。単位を持たない整数値である必要があります。width
The intrinsic width of the image in pixels. Must be an integer without a unit.
画像固有の幅をピクセル単位で指定します。単位を持たない整数値である必要があります。
となっており、全く別物なのです。
もう少し深堀りして、Living Standardのドラフトを確認してみます。
<img>はHTML5から、埋め込みコンテンツ(Embedded content)という扱いで、そのwidthとheightに関しては、Dimension attributesという項目にあります。
そして、そこでは、
The width and height attributes on img, iframe, embed, object, video, source when the parent is a picture element and, when their type attribute is in the Image Button state, input elements may be specified to give the dimensions of the visual content of the element (the width and height respectively, relative to the nominal direction of the output medium), in CSS pixels. The attributes, if specified, must have values that are valid non-negative integers.
img、iframe、embed、object、video、親要素にpictureを持つsource、Type属性がImage Buttonなinputで、ビジュアルコンテンツのディメンションをCSS pixelで指定する
となっています。
これをシンプルにしたのが、MDNの説明というわけです。
さらに、Noteにはこんな一文もあります。
The dimension attributes are not intended to be used to stretch the image.
dimension属性は、画像の引き伸ばしに使用することを意図していない。
HTML4.01の説明がバッサリと否定されている感じです。
表示のコントロールはCSSで行うのがあたりまえな現状を考えれば、widthとheightは埋め込まれるコンテンツ(データ)のディメンションを指定するための属性と考えて良さそうです。
ただし、例外もあります。それは、サイズ固定の画像のためのレスポンシブイメージを、デバイスのピクセルレシオ(DPR)に基づいて構成する場合です。この場合は、(ソースの選択のために)widthとheightで表示サイズを指定することになります。
そして、この影響を受けるのがGatsbyImageやnext/imageでレイアウトモードを「Fixed」に設定した場合となります。next/imageの場合は「intrinsic」に設定した場合も含まれます。
Fixedとそれ以外のモードでは、widthとheightで設定するものが異なるわけです。
(next/imageのデフォルトとなっているintrinsicも、基本的にはFixedと同じです。intrinsicがデフォルトなあたりからNext.jsの方向性が見える気がします。)
レスポンシブイメージが導入された頃には、<img>のwidthとheight属性は設定しないという流れもありました。そのまま、属性をなくしたら?なんて話が出ていた覚えもあります。
身近で重要な存在のわりには、その扱いはコロコロと変わっています。そして、現在では、レイアウトシフト対策で非常に重要な属性です。
一度、再確認をオススメします。
next/imageやGatsbyImageが出力するコードは、単純なレスポンシブイメージではなく、なかなか興味深いことをしています。
機会があればこのあたりもまとめたいと思います。