LoginSignup
17
7

More than 3 years have passed since last update.

次世代Webスタイリングを追う ーScroll Snap, :focus-within, @media (prefers-*), :is()

Last updated at Posted at 2019-12-15

こちらは「DeNA Advent Calendar 2019」 の16日目です。
今年は「20新卒のAdvent Calendar」もありますので、よかったら合わせてご覧ください。

概要

Chrome Dev Summit 2019 にて、「 Next-generation web styling 」というセッションがありました。このセッションでは、CSSのセレクタやプロパティをはじめとするWebスタイリングにまつわる多くの新しいTipsが紹介されています。

セッション内の全てのTipsを手を動かしながら確認したかったんですが、色々と間に合いませんでした。なので、現時点で僕が理解できた(であろう)内容を記載したいと思います。

本記事で紹介するTips

本記事では、セッションの前半で紹介されているこちらのTipsを紹介します。

記載しているサンプルとソースコードは、こちらで公開しています。よかったらご覧ください(随時更新予定)。

それでは見ていきましょう/

CSSプロパティ: Scroll Snap

トップバッターは Scroll Snap 。新しいCSSのプロパティです。

このプロパティを指定することで、スマホのホーム画面のスクロールのように、スクロールした後に特定の要素にsnapするようになります。CSSだけでこれを表現できるのは嬉しいですね。

サンプル

水平軸のスクロールで、snap対象の要素を中央に表示させるようにしています(サンプルのURL)。

scroll-snap

HTML
<div class="container">
  <img src="1.png" width="300" height="300">
  <img src="2.png" width="300" height="300">
  <img src="3.png" width="300" height="300">
  <img src="4.png" width="300" height="300">
  <img src="5.png" width="300" height="300">
</div>
CSS
.container {
  display: flex;
  height: 300px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
}
.container img {
  scroll-snap-align: center;
}

scroll-snap-type: スクロール方向を指定。今回は水平軸(x)でしたが、垂直軸(Y)や両軸(both)などもあります。実際の挙動はこちらで確認ください。

scroll-snap-align: snap対象の要素をどの位置に表示するかを指定。今回は中央(center)でしたが、先頭(start)や後尾(end)にもすることができます。

overscroll-behavior: Scroll Snapと合わせたい代物です。これは、スクロールの連鎖を抑制します。何が嬉しいのかというと、Scroll Snapのエリアをスマホで左にスクロールし続けた場合、ユーザーの意図とは反してブラウザバッグする可能性があります。そんな事故防止に効果的です。

ブラウザの対応状況

CSS property: scroll-snap-type CSS property: scroll-snap-align
scroll-snap-type
caniuse.com
scroll-snap-align
caniuse.com

参考資料

CSSセレクタ: :focus-within

次にCSSセレクタに新しく追加された :focus-within です。これは、その要素自体がフォーカスされているか、または、その要素の子孫がフォーカスされているかを表現することができます。

サンプル

入力欄がフォーカスされた時に親要素の背景色と、その子要素の画像をアニメーションさせています(サンプルのURL)。Chrome DevToolsでも:focus-withinに切り替えることができます。

:focus-within

HTML
<div class="container">
  <img src="1.png" width="50" height="50">
  <input type="text" value="" placeholder="Please focus...">
</div>
CSS
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}
.container img {
  transition: all .5s;
  opacity: .25;
}
.container:focus-within {
  background-color: #2c8898;
}
.container:focus-within img {
  opacity: 1;
  transform: rotate(360deg);
}

ブラウザの対応状況

CSS selector: :focus-within
:focus-within
caniuse.com

参考資料

メディアクエリ: @media (prefers-reduced-motion)

激しいアニメーションが苦手な方に向けて、「視差効果を減らす」という設定メニューがあります(初耳だった)。iPhoneはこちらのサポートページの通り、設定メニューがありました。

そしてWebコンテンツも、prefers-reduced-motion を使うことで、視差効果を減らしたいユーザー向けにCSSを記述できるようになりました。

サンプル

意味もなく激しく動くアニメーションを、視差効果を減らしたいユーザーには静止して表示します(サンプルのURL)。

なお、Chrome DevToolsのシミュレーターは、Chrome 79で対応ということです。それまではCanaryで開発すると良いと思います。

prefers-reduced-motion

HTML
<div class="container">
  <div class="motion">
    <img src="1.png" width="50" height="50">
    <img src="2.png" width="50" height="50">
    <img src="3.png" width="50" height="50">
    <img src="2.png" width="50" height="50">
    <img src="1.png" width="50" height="50">
  </div>
</div>
CSS
.container {
  position: relative;
  height: 300px;
}
.motion {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  display: flex;
  justify-content: space-around;
  animation: MoveUpDown 1s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .motion {
    top: 50%;
    transform: translateY(-50%);
    animation: none;
  }
}
@keyframes MoveUpDown {
  0%, 100% { top: 0; }
  50% { top: 250px; }
}

.motionで上下にアニメーションを行なっており、@media (prefers-reduced-motion: reduce)を使って、アニメーションを打ち消しています。

ブラウザの対応状況

一生懸命がんばって作ったアニメーションが...という心の悲鳴が聞こえてきそうですが、ブラウザは大方対応できているようです。

prefers-reduced-motion media query
prefers-reduced-motion
caniuse.com

参考資料

メディアクエリ: @media (prefers-color-scheme)

macOS Mojaveにて、OSレベルで外観をdarkモードに変更できるようになりました(僕はまだdarkモードに慣れずにいます)。

そしてWebコンテンツも、prefers-color-scheme というメディアクエリを用いて、light/darkごとにCSSで表現できるようになりました。

サンプル

背景色と文字色をモードごとに切り替えるサンプルです(サンプルのURL)。prefers-reduced-motionと同じく、Chrome DevToolsのシミュレーターはChrome 79で対応ということです。

prefers-color-scheme

HTML
<div class="container">
  <p>Hello</p>
  <p>你好</p>
  <p>こんにちは</p>
  <p>안녕하세요</p>
  <p>السلام عليكم</p>
</div>
CSS
:root {
  --theme-font: #0f0f0f;
  --theme-background: #ffffff;
}
@media (prefers-color-scheme: dark) {
  :root {
    --theme-font: #ffffff;
    --theme-background: #0f0f0f;
  }
}
.container {
  background-color: var(--theme-background);
  color: var(--theme-font);
}

CSSのカスタムプロパティを使い、初期値のlightモード用のカラーコードをdarkモード時にはdarkモード用のカラーコードに上書きするようにしています。そのため、背景色と文字色はカスタムプロパティを参照すればlight/darkそれぞれのモード用に色を切り替えることができます。

ブラウザの対応状況

ブラウザもだいぶ対応されてきている状況です。iOSアプリでは、darkモード対応を推奨しているので、WebViewの開発担当者をはじめ、darkモードの対応が今後増えてくると思います。

prefers-color-scheme media query
prefers-color-scheme
caniuse.com

参考資料

CSSセレクタ: :is()

最後に、新しくCSSに追加されそうな :is() セレクタについてです。このセレクタを使うと、CSSを少しだけシンプルにすることができます。

サンプル

:is()のサンプルです(サンプルのURL)。例えば、記事の見出し(h1 ~ h6)のスタイルを統一したいときに、これまで下記のようにCSSを書いてきたかと思います。

CSS
article > h1, article > h2, article > h3,
article > h4, article > h5, article > h6 {
  color: #0f4c81;
}

これに :is() を使うと、以下のようにシンプルに記載することができます。

CSS
article > :is(h1, h2, h3, h4, h5, h6) {
  color: #0f4c81;
}

ブラウザの対応状況

使う場面けっこうありそうですが、ブラウザの対応状況は待ちの状況。期待して待っていましょう/

CSS selector: :is()
:is()
caniuse.com

参考資料

おわりに

Next-generation web stylingのセッションでは、他にも多くの新しいWebスタイリングのTipsが紹介されています。Gap / Logical Properties / Subgrid / Paint API / Houdini ...。

お腹いっぱいになりそうですが、サービスの使い心地を少しでも高めるためにもぜひキャッチアップしていきたいと考えています。また、試作品ができてきたら公開していきます。

以上、ご覧くださりありがとうございました。

17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7