iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

最近の CSS の機能を試してみた

はじめに

こんにちは。iimon でエンジニアをしている保田です。 最近 CSS を触る機会が減ったこともあり、ここ数年で追加された CSS や一部あまり使ったことのない CSSを見たり試したりしてみました。 それぞれの詳細を詳しく解説していくと中には1記事分ぐらいになってしまうので、今回はそれぞれの機能を簡単に紹介していこうと思いました。

text-wrap: balance

テキスト行の文字数を均等にして折り返すことができる新しいプロパティです。 https://developer.mozilla.org/ja/docs/Web/CSS/text-wrap

設定方法

.text {
  text-align: center;
  text-wrap: balance; /* 各行の文字数を均等に調整 */
}

適用後

各行の文字数がより均等になり、バランスが改善されていることがわかります。

initial-letter

新聞や雑誌でよく見る「ドロップキャップ(drop cap)」を CSS だけで簡単に実装できる機能です。 https://developer.mozilla.org/ja/docs/Web/CSS/initial-letter

設定方法

.paragraph::first-letter {
  initial-letter: 3; /* 3行分の高さ */
  font-weight: bold;
  color: #2563eb;
}

適用後

使用頻度は確かにそれほど高くありませんが、ドロップキャップを簡単に実装できるということは覚えておくと、無駄に時間をかけずに実装できるので便利だと思いました。

新しい単位(lvh,svh,dvh)

今までは vw、vh、vmin、vmax などの単位がありましたが、 新たに以下のビューポート単位が追加されました。

  • svh(Small Viewport Height): 最小のビューポート高さ(UI が表示された状態)
  • lvh(Large Viewport Height): 最大のビューポート高さ(UI が隠れた状態)
  • dvh(Dynamic Viewport Height): 動的なビューポート高さ(UI の表示状態に応じて変化)

すべてには触れませんが、この中でも一番便利だなと思ったのはdvh です。 今までは、画像を端末幅にぴったり合わせるためには、javascript で端末幅を取得して、その幅に合わせて画像の幅を設定をしないと iOSSafari ではアドレスバーなどを除いた高さに設定ができませんでした。

参考サイト blog.minoru.dev

dvh を使用することによって、iOSSafari でもアドレスバーなどを除いた高さに設定できるようになったのはかなり便利になったなと思いました。

設定方法

.container {
  height: 100svh;
  min-height: 100lvh;
  max-height: 100dvh;
}

アドレスバーとは以下画像のスマホの下部に表示されているものです。

CSS ネスト

いつのまにか Sass なしで CSS のネストが使えるようになっていました。 今までは Sass のようにネストして記述することができませんでしたが、CSS ネストを使用することによってネストして記述することができるようになりました。 CSS のネストが使えるのは個人的には結構嬉しいです。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_nesting

設定方法

.parent {
  color: blue;

  & .child {
    color: red;
  }

  &:hover {
    background-color: yellow;
  }
}

カスケードレイヤー

カスケードレイヤーとは、CSS の新しい機能で、スタイルの優先順位を階層的に管理できる機能です。

従来の問題点

これまでの CSS では、以下のような問題がありました。

  1. より強いセレクタで上書きしようとする
  2. !important などで優先度を強制的に上げる
  3. どのスタイルが最終的に適用されるか分からない
/* 問題のあるコード例 */
.button {
  background: blue;
}
.header .button {
  background: red;
}
.header .nav .button {
  background: green;
}
.header .nav .button.special {
  background: yellow !important;
}

カスケードレイヤーでの解決

レイヤーを使うことで、詳細度に関係なく明確な優先順位を設定できます developer.mozilla.org

/* レイヤーの優先順位を事前に定義 */
@layer reset, base, components, utilities;

@layer base {
  .button {
    background: blue;
    padding: 8px 16px;
  }
}

@layer components {
  .button-primary {
    background: green;
  }
}

@layer utilities {
  .bg-red {
    background: red; /* 詳細度が低くても確実に適用される */
  }
}

メリット

  • レイヤーの順序で決まるため予測しやすい
  • !importantや複雑なセレクタが不要
  • 統一された CSS 設計ルールを作りやすい

@scope アットルール

@scope とは、 これを使用すると、スタイルを適用するスコープを HTML の特定の部分に限定することができます。 開始点と終了点も指定することができます。

https://developer.mozilla.org/ja/docs/Web/CSS/@scope

設定方法

@scope (スコープルート) to (スコープリミット) {
  /* ルールセット */
}

/* (.section内のpのみに適用) */
@scope (.section) {
  p {
    color: green;
  }
}

/* (.section_footer から .section_footer_textarea_inner までの p に適用) */
@scope (.section_footer) to (.section_footer_textarea_inner) {
  p {
    color: green;
  }
}

@starting-style

@starting-style は、トランジションの開始時のスタイルを定義することができます。 CSS では display:none と指定しているものを、display:block にしたときなどに、アニメーションが適用されません。 これを使用すると、トランジションされる要素に対して、初期スタイルを定義することができます。

設定方法

.open-content {
  display: none;
  width: 100px;

  @starting-style {
    width: 0px;
  }
}

.open {
  display: block;
  transition: width 4s;
}

Scroll-driven Animations

スクロール位置に応じてアニメーションを制御できる機能です。パララックス効果やスクロールに連動したフェードイン・アウト効果を、JavaScript を使わずに CSS だけで実装できます。

設定方法

/* スクロールでフェードインする要素 */
.fade-in-element {
  animation: fade-in linear;
  /* ページ全体のスクロール位置をアニメーションの基準にする */
  animation-timeline: scroll();
  /* 要素が画面に入り始めてから完全に表示されるまでアニメーション実行 */
  animation-range: entry 0% entry 100%;
}

/* スクロールでスライドインする要素 */
.slide-in-element {
  animation: slide-in linear;
  animation-timeline: scroll();
  animation-range: entry 0% entry 100%;
}

/* フェードインアニメーション */
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* スライドインアニメーション */
@keyframes slide-in {
  from {
    opacity: 0;
    transform: translateX(-50px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

margin-inline:auto

要素をセンター寄せにしたい場合、よくmargin: 0 autoなどを使用したりすることもあると思いますが、 これは、従来のmargin: 0 autoの論理プロパティ版で、インライン方向のマージンを設定することができます。 論理プロパティとは、書字方向(left-to-right または right-to-left)に関係なく適切に動作するプロパティです。 今後は margin-inline:auto を使用していきたいと思いました。

設定方法

.container {
  margin-inline: auto;
  width: 80%;
}

inset:0

top: 0; right: 0; bottom: 0; left: 0;を短縮して記述できるプロパティです。オーバーレイやモーダルの作成、要素を親要素いっぱいに広げる際に便利だと思いました。

設定方法

.overlay {
  position: absolute;
  inset: 0;
}

.modal {
  position: fixed;
  inset: 20px;
}

place-items: center;

Grid Layout または、 Flexbox で、子要素を縦横中央に配置できます。align-items: centerjustify-items: centerを同時に指定するショートハンドプロパティです。

設定方法

.grid-container {
  display: grid;
  place-items: center;
}

.flex-container {
  display: flex;
  place-items: center;
}

revert

プロパティをブラウザのデフォルトスタイルに戻すキーワードです。カスタムスタイルをリセットして、ブラウザ本来のスタイルに戻したい場合に使用します。initialunsetとは異なり、ユーザーエージェントスタイルシートの値に戻ります。 特定のビューポートでのみ以前のスタイルを適用したい場合とかなどに使えるのかなと思いました。

設定方法

.element {
  all: revert;
}

.button {
  background-color: revert;
  border: revert;
}

place-content: center

Grid Layout やFlexboxnなどで縦横中央に配置することができます。 align-content: centerjustify-content: centerを同時に指定するショートハンドプロパティです。コンテンツ全体を中央揃えしたい場合に便利です。

設定方法

.grid-container {
  display: grid;
  place-content: center;
  height: 100vh;
}

width: fit-content

要素の幅をコンテンツの幅に合わせて自動調整できます。 コンテンツが少ない場合は必要最小限の幅にすることができます。

設定方法

.text {
  width: fit-content;
  margin-inline: auto;
  background: #000;
  color: #fff;
}

適用後

any-hover: hover

バイスがホバー操作に対応しているかを判定できるメディアクエリです。 タッチデバイスでホバーが動作しないように考慮することは大切です。 考慮されていない場合、ホバーされている要素をダブルタップしないと反応しないようなことも起こりえます。 今までは判別するために、@media (hover: hover) and (pointer: fine)を使用して、入力デバイスがホバーに対応しているかつ、マウスのようなポインターが使用されている場合のようにPC判定させて、その中にホバー時の設定をよく行なっていたりもしていました。

hoverメディア特性には以下のものがあります。

@media (hover: hover) 主な入力デバイスがhoverに対応しているか
@media (any-hover: hover) 入力デバイスのいずれかにhoverに対応している入力デバイスが含まれているか

@media (hover: hover)でもホバーが可能なデバイスを判別できることは同じですが、 @media (any-hover: hover)のほうが詳細にホバーが可能なデバイスを判別できることができます。

例えばスマートフォンタブレット端末はタッチデバイスであるため、hoverが動作しないデバイスとして認識されます。 しかし、タブレット端末にマウスやトラックパッド付きのキーボードを接続した場合、(any-hover: hover)ではhoverが動作するデバイスとして正しく判定されますが、一方で(hover: hover)ではこの判定が適用されません。 ユーザーの実際の使用環境に応じて適切に判定するためには、any-hoverメディア特性を活用することをお勧めします。

設定方法

@media (any-hover: hover) {
  .a:hover {
    background-color: #007bff;
  }
}

まとめ

便利な機能が増えているなという印象で、すぐ使えそうなものは使ってみようかと思いました。 また知らないことで、無駄に遠回りな実装をしてしまったり、余計なスタイルを書いてしまうこともあると思うので、CSS キャッチアップは今後も続けていこうと思いました。

この記事を読んで興味を持って下さった方がいらっしゃればカジュアルにお話させていただきたく、是非ご応募をお願いします!

iimon 採用サイト / Wantedly / Green