CSSで実装する時、フロントエンドのデベロッパーは何を考え、どういうことに配慮して実装するのか
Post on:2022年11月24日
UIコンポーネントをCSSで実装する時に、何を考えながら実装するのか、どういうことに配慮して実装するのかを紹介します。
CSSの何を使用して配置するのかベストか、レスポンシブの対応方法をはじめ、グラデーションをより美しく実装する方法、clamp()
によるフォントサイズの定義、論理プロパティの使用など、CSSの実践的なテクニックについても解説されています。
Inside the mind of a frontend developer: Hero section
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- 実装するヒーローコンポーネント
- HTMLの構造を考える
- グラデーションの背景
- 疑似要素
- スマホでの表示を考える
- ヒーローの最小高さ
- 配置のためのCSS Gridとその際の課題
- コンテンツの中央配置
- スマホでグラデーションを変更する
- グラデーションをより美しく実装する
- clamp()によるフォントサイズの定義
- 論理プロパティを使用したグラデーション
- コンテンツの最大幅を考える
- 画像のフォールバックにカラーを設定しておく
- 上部に固定ヘッダがある場合
- 終わりに
はじめに
UIコンポーネントをHTMLとCSSで実装することは、まぁ答えは分かれますが、簡単あるいは難しいとも言えます。最近ではUIの実装を素早くできるフレームワークやツールがたくさんありますが、それらはどれほど良いものなのでしょうか。
CSSはここ数年で、本当に興味深い便利な機能をたくさん手に入れました。これらにより、もちろんCSSが難しいということではなく、フロントエンドのデベロッパーの仕事はさらに難しくなりました。UIを実装するためのオプションやソリューションがたくさん増えたということが現在の課題です。すでに同じように感じている人もいると思います。
とは言え、フロントエンドのデベロッパーがコンポーネントの実装に取り組んでいるときの頭の中を覗いてみるのは興味深いことだと思います。ここでもっとも重要なことは、CSSの結果ではなく、実装に取り組んでいるときの思考プロセスです。
この記事では、私の思考プロセス、なぜ他のソリューションではなくそのソリューションを選択したのか、その長所と短所、そして潜在的な課題や問題があるかどうかを示すことで、ヒーローセクションを実装する旅に招待したいと思います。
準備はできましたか?
では、フロントエンドのデベロッパーの頭の中を覗いてみましょう。
実装するヒーローコンポーネント
「こんなシンプルなヒーローコンポーネントに対するあなたの考え方を示すために記事を書くのですか?」と思うかもしれません。
このようなコンポーネントを構築し、さまざまなコンテンツのバリエーションに対応できるようにするには、実際に考え、声に出して話したり、自分自身に質問をしたりする必要があります。
ヒーローコンポーネント
このデザインを見て最初に頭に浮かんだことは、レイアウトです。レイアウトがどのように機能すればよいのか?
最初にレイアウトの機能を考える
ポイントは、3つあります。
- コンテンツには、見出し、パラグラフ、リンクがある。
- フェードのグラデーション。
- 全幅の背景画像。
HTMLの構造を考える
ヒーローのアイテムはすべて積み重なっています。レイアウトの観点からは、グラデーションのあるコンテンツがヒーローの幅の約60%を占めているように見えます。実際には、グラデーション要素は全幅を占めるかもしれませんが、グラデーション自体が幅を占めることはないはずです。
HTMLでマークアップするには、まずは上記のアイテムを積み重ねて実装します。方法はまだ不明です、何を使用して配置すればよいでしょうか? 私の頭の中では絶対位置指定がデフォルトですが、CSS Gridでも同じことができると思います。
HTMLの観点から私が記述したコードは次のとおりです。
1 2 3 4 5 6 |
<section class="hero"> <div class="wrapper hero__wrapper"> <div class="hero__content"></div> <img src="berries.jpg" alt="" /> </div> </section> |
コンテンツと画像は、簡単です。考えさせられたのは、グラデーションという厄介なものです。ラッパーをグラデーションの背景にするか、それとも別の要素(疑似要素または追加の<div>
)で実装するかです。
グラデーションの背景
今回はラッパーではなく、.hero__content
に背景を追加することを考えました。よくよく検討してみると、.wrapper
の最大幅では大きなスクリーンでは機能しないことが分かります。
グラデーションの背景
疑似要素
そのためには、ヒーロー全体をカバーする要素が必要です。理想としては、要素を.hero
セクションに絶対位置で配置することで実装していました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.hero { position: relative; } .hero:after { content: ""; position: absolute; inset: 0; background: linear-gradient(to right, #000 35%, transparent) left center/100% no-repeat; } /* コンテンツをグラデーションの上に配置するには、これが必要です。 */ .hero__content { position: relative; z-index: 1; } |
このCSSは確かに機能しますが、後ほどposition: absolute;
の代わりにCSS Gridのスタッキングを使用する別のソリューションを解説します。
スマホでの表示を考える
スマホではどのように表示すればよいのでしょうか?
たとえば、グラデーションを下から上にフェードする必要がありますか? あるいは、代わりに単色にする必要がありますか? このコンポーネントが使用される場所に基づいて、スマホで異なるバリエーションを持つ必要がある場合はどうしたらよいでしょうか?
スマホでの表示はどうすればよいか?
CSSで両方のユースケースを考慮することで、将来的に新しいバリエーションを構築しようとするときに多くの時間を節約できます。ありがたいことに、上記のCSSは、両方のソリューションを機能させることができます。
ヒーローの最小高さ
ヒーローはいかなる場合でも、高さを固定してはならないことに同意します。コンテンツは動的なものであり、いつでも変更できます。
私がそういうときによく使用するのは、min-height
の値に固定値と動的値を組み合わせます。
1 2 3 |
.hero { min-height: calc(300px + 15vw); } |
このCSSがあれば、小さなスクリーンで高さを変更するためのメディアクエリを使用する必要はなくなります。
あと、垂直のパディングも必要ですね。非常に長いコンテンツがある場合、端に重ならないようにするために非常に重要です。
フロントエンドのデベロッパーは、問題がまだ見えていないと細部を見落としてしまうことがありますが、実装中にこういったエッジケースを思い出すことは非常に重要です。
1 2 3 4 5 |
.hero { min-height: calc(300px + 15vw); padding-top: 1rem; padding-bottom: 1rem; } |
このCSSで上下に垂直のパディングが確保されます。
上: パディングなし、下: パディングあり
配置のためのCSS Gridとその際の課題
ヒーローの各アイテムを重ねるためにCSS Gridを使用するには、マークアップで画像を上に移動して.hero
の直接の子にする変更が必要です。
1 2 3 4 5 6 |
<section class="hero"> <img class="hero__image" src="berries.jpg" alt="" /> <div class="wrapper hero__wrapper"> <div class="hero__content"></div> </div> </section> |
マークアップを変更すると、CSS Gridで配置できます。
1 2 3 4 5 6 7 8 9 10 |
.hero { display: grid; min-height: calc(300px + 15vw); } .hero__image, .hero__content, .hero:after { grid-area: 1 / -1; } |
これでヒーロー画像、コンテンツ、およびグラーデションが同じグリッド領域に配置され、互いに積み重ねられます。
ただし、欠点が1つあります。縦長の画像を追加した場合に、ヒーローの高さを制御できません。<img>
要素にmax-height
を設定することはできますが、ヒーローセクションの高さが画像より大きくなってしまいます。
ヒーローセクションの高さが画像より大きくなる
min-height
をheight
に置き換えることで解決できますが、これは完璧な基準に反しています!
1 2 3 4 5 6 |
.hero { display: grid; height: calc(300px + 15vw); } /* ほかのスタイル */ |
これは確かに機能するのですが、コンテンツが固定された高さを超えて大きくなると、問題が発生します。この問題については記事で解説したので、ご覧ください。
コンテンツの中央配置
コンテンツは垂直方向の中央に配置され、左揃えになります。現在サポートが充実しているFlexboxに慣れてしまっているので、以前の中央配置のテクニックを使用する必要はありません。
中央配置にFlexboxを使用する場合の欠点は、入れ子が多すぎることです。コンテンツに到達するには、Flexboxを3レベル用意する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.hero { display: flex; flex-direction: column; } .hero__wrapper { flex: 1; display: flex; flex-direction: column; } .hero__content { flex: 1; display: flex; flex-direction: column; justify-content: center; } |
もっとシンプルに実装できないでしょうか?
そうです、CSS Gridを使用すれば、方向やセンタリングのプロパティが少なく済みます。
1 2 3 4 5 6 7 8 9 10 |
.hero { display: grid; /* ほかのスタイル */ } .hero__wrapper { display: grid; place-items: center start; /* ほかのスタイル */ } |
こっちのCSSの方がいいですね! CSS Gridの勝ちです。
この瞬間を楽しみながら、コンテンツの位置を変える可能性について少し考えてみました。
多くの場合、デザインチームやプロダクト担当者は創造性を発揮して、次のような質問をします。
ねぇ、これがこういうデザインのは知っているけど、位置を中央上部に変更することはできますか?
ありがたいことに、CSS Gridを使用すると、こういったことにも簡単に対応できます。何の問題もなく好きな位置に変更できます。
CSS Gridだと位置変更の対応も簡単
スマホでグラデーションを変更する
私はデスクトップ用のCSSの基礎が出来てから、スマホ用のスタイルを書くことを考えることが多いです。私はこういうアプローチをしていますが、それはもちろんあなた次第です。
デスクトップ用のCSSの基礎が出来てから、スマホ用のスタイルを考える
スマホでは、グラデーションは下から上に向かっており、コンテンツは一番下に配置されます。CSS変数で方向を保存しておけば、background
プロパティ全体を上書きする代わりに、方向を変更できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.hero { --gradient-dir: to top; } .hero:after { background: linear-gradient(var(--gradient-dir), ...); } @media (min-width: 800px) { .hero { --gradient-dir: to right; } } |
次に、コンテンツをラッパーの最後になるように配置する必要があります。ここではplace-content
を使用しているので、これは簡単に実装できます。
1 2 3 4 5 6 7 8 9 |
.hero__wrapper { place-content: end start; } @media (min-width: 800px) { .hero__wrapper { place-content: center start; } } |
グラデーションをより美しく実装する
主要な問題は解決したので、次はグラデーションをより美しく実装することに集中します。CSSのデフォルトのグラデーションで私が気に入らないのは、目に負担がかかりすぎることです。その問題に関するCSSWGの提案がありますが、2022年11月現在どのブラウザにもサポートされていません。
上: デフォルト、下: 美しく実装したグラデーション
ありがたいことに、Andreas Larsenが緩和された美しいグラデーションを生成する便利なツール「Easing Gradients」をリリースしています。
デフォルトのグラデーションは次のとおりです。
1 2 3 4 |
.hero:after { background: linear-gradient(to right, #000 35%, transparent) left center/100% no-repeat; } |
「Easing Gradients」を使用すると、最初と最後のカラーストップを入力し、あとは3次ベジエを自由にコントロールできます。
Easing Gradients
グラデーションが将来的にどうなるかは、こんな感じです。
1 2 3 4 5 6 7 8 9 |
/* これはまだ提案段階です。 どのブラウザでも動作しません。 */ .hero:after { linear-gradient( to bottom, hsla(330, 0%, 0%, 1), cubic-bezier(0.42, 0, 0.39, 0.26), hsla(210, 0%, 0%, 0) ); }; |
現在のところ、ツールでは下記のように多くのカラーストップを含むCSSを生成します。これはまったく問題なく、理解しやすいコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.hero:after { background: linear-gradient( to right, hsl(0, 0%, 0%) 0%, hsla(0, 0%, 0%, 0.995) 8.2%, hsla(0, 0%, 0%, 0.981) 16%, hsla(0, 0%, 0%, 0.958) 23.4%, hsla(0, 0%, 0%, 0.926) 30.4%, hsla(0, 0%, 0%, 0.885) 37.3%, hsla(0, 0%, 0%, 0.835) 43.8%, hsla(0, 0%, 0%, 0.776) 50.2%, hsla(0, 0%, 0%, 0.709) 56.5%, hsla(0, 0%, 0%, 0.633) 62.6%, hsla(0, 0%, 0%, 0.548) 68.7%, hsla(0, 0%, 0%, 0.455) 74.8%, hsla(0, 0%, 0%, 0.354) 81%, hsla(0, 0%, 0%, 0.244) 87.2%, hsla(0, 0%, 0%, 0.126) 93.5%, hsla(0, 0%, 0%, 0) 100% ) left center/100% no-repeat; } |
そして最後にちょっとした工夫として、グラデーションの不透明度を0.1だけ下げてみてください。そうすることで、よりリアルになります。
clamp()によるフォントサイズの定義
CSSのclamp()
関数がブラウザにサポートされたので、私は流動的なフォントサイズの定義にはメディアクエリよりもclamp()
関数を使用することを好んでいます。
1 2 3 4 5 6 7 |
.hero__headline { font-size: clamp(1.35rem, 6vw, 2.15rem); } .hero p { font-size: clamp(1rem, 5vw, 1.25rem); } |
論理プロパティを使用したグラデーション
アラビア語などの右から左へのドキュメントで、ヒーローが期待通りに機能するようにするには、グラデーションも反転させる必要があります。と、そんなことを考えているときに、グラデーションにCSSの論理プロパティを使用するアイデアをツイートしました。
グラデーションにCSSの論理プロパティを使用
論理プロパティinline-end
を使用すれば、ltrの場合はto right
になり、rtlの場合はto left
になります。
1 2 3 |
.hero { background: linear-gradient(to inline-end, #000, transparent); } |
現状では、CSS変数を使用して、ルートドキュメントの方向に応じて変更することが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.hero { --gradient-dir: to top; } .hero:after { background: linear-gradient(var(--gradient-dir), ...); } @media (min-width: 800px) { .hero { --gradient-dir: to right; } html[dir="rtl"] { .hero { --gradient-dir: to left; } } } |
コンテンツの最大幅を考える
グラデーションはヒーローセクション全体をカバーしていないので、テキストはグラデーションの境界内に収める必要があり、読みやすく、アクセシブルである必要があります。
そのためにはmax-width
にch
単位を使用すると、このユースケースに完璧にフィットします。
テキストはグラデーションの境界内に収めたい
これを実現するためには、.hero__content
要素に最大幅を定義します。
1 2 3 |
.hero__content { max-width: 65ch; } |
最大幅が設定されたので、下記のように表示されます。
テキストが読みやすくなる
画像のフォールバックにカラーを設定しておく
画像の上にテキストを配置する際に、私は通常<img>
にbackground-color
を追加することで、防御的なCSSのアプローチをおこないます。グラデーションがあるので、今回は必要ありません。
上部に固定ヘッダがある場合
場合によっては、ヘッダがヒーローセクションの上部に配置されることがあるかもしれません。その場合は、ヘッダ・ナビゲーションの高さに等しい量で、ヒーローのpadding-top
を増加させます。
上部に固定ヘッダがある場合
わたし達にできることは、padding
の量を増やすことです。これでヒーローに余裕を持たせることができます。
1 2 3 |
.hero--with-nav { padding-top: 3rem; } |
:has()
のサポートが十分になれば、下記のようになるかもしれません。
1 2 3 |
html:has(.site-header--fixed) .hero { padding-top: 3rem; } |
このCSSで.site-header--fixed
の固定ヘッダがある場合にのみ、padding-top: 3rem;
が設定されます。
上部に固定ヘッダがある場合
終わりに
この記事では、私がヒーローセクションを実装するときにどのように考えたかについて楽しんでいただけたでしょうか。このプロセスは長すぎると感じた人もいるかもしれませんが、クライアントのために実物を実装しながら素早く考え、決定するので、通常ははるかに短い時間で作業は完了します。
この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors