BLOG
新しい疑似クラス:has() :modal :is() :where()を使ってみた!
INDEX
EvoLab.のブログでは初めての登場になります、エンジニアのタケモトです。
今回は、近年各種ブラウザでサポートされはじめた疑似クラスについて、いくつかご紹介します。
まだ全てのブラウザで完全にサポートされていませんが悪しからず。
:has()
:has()
は特定の要素を持つ要素を指定する擬似クラスです。
具体的には、:has()
のカッコ内にあるセレクタに該当する子要素を持つ親要素にスタイルを当てることができます。
現段階では、親要素を変化させるときはJavaScript(jQuery)を使用する必要があるので、:has()
が使用できるようになると便利な世の中になります。
HTML・css(一部抜粋)は以下になります。
HTML
<div>
<ul class="list">
<li class="item">
<h2>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<p>Lorem ipsum dolor sit amet, <a href="#">consectetur adipisicing elit</a>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<h3>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h3>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<figure>
<img src="https://source.unsplash.com/bIhpiQA009k" alt="">
<figcaption>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</figcaption>
</figure>
</li>
<li class="item">
<h2>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h2>
<p class="active">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</li>
<li class="item">
<h2>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore <a href="#">et dolore magna</a> aliqua.</p>
<figure>
<img src="https://source.unsplash.com/bIhpiQA009k" alt="">
</figure>
</li>
</ul>
</div>
CSS (SCSS)
:has()
ではタグの指定だけでなく、class名を指定することも可能です。
隣接セレクタや直下セレクタにも使えちゃいます。
めちゃくちゃ便利です。
li {
background-color: $gray;
&:has(.active) { // activeというclassを子要素に持つliタグの背景色変更
background-color: $yellow;
h2 {
color: $white; // activeというclassを子要素に持つliタグの子要素のh2タグのテキストカラー変更
}
}
}
h3 {
&:has(+ p) { // 後続する要素がpタグの場合テキストカラー変更
color: $white;
}
}
p {
&:has(a) { // aタグを子要素に持つpタグのテキストカラー変更
color: $yellow;
}
}
figure {
&:has(> figcaption) { // figcaptionを子要素に持つfigureタグにフィルターをかける
img {
filter: blur(4px);
}
}
}
デモ
2022年9月現在ではFirefox以外のモダンブラウザで対応可能のようです。
":has()" | Can I use... Support tables for HTML5, CSS3, etc
:modal
:modal
が使用できる条件は
- showModalメソッドを使用するdialog要素
- フルスクリーン モードになっている要素
になります。
今回はshowModalメゾットを使用してデモサイトを作成しました。
HTML・CSS・JS(一部抜粋)は以下になります。
HTML
:modal
が使用できる条件に沿って、dialog要素を使用してモーダルを作成しています。
モーダルを表示するトリガーボタンを2つ用意し、data属性をつけることでJSの処理を区別します。
※dialog要素についてはこちら
<div class="wrapper">
<button class="btn" data-modal="true">:modal を使用</button>
<button class="btn" data-modal="false">:modal を使用しない</button>
</div>
<dialog id="modal" class="modal">
<div class="content">
<h2 class="title">タイトルタイトルタイトル</h2>
<div class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
<button id="close" class="close">
<span class="line line--top"></span>
<span class="line line--bottom"></span>
</button>
</div>
</dialog>
JS
以下のようにJSの処理を分けることで、:modal
が使用できるボタン・使用できないボタンを作成しています。
- ボタンのdata属性がtrue → showModalメゾットを使用してモーダルを表示させ、
:modal
が使用可能 - ボタンのdata属性がfalse → showModalメゾットを使用しないため、
:modal
が使用できない
どちらのパターンでも modal.close();
でモーダルを閉じることができます。
const btns = document.querySelectorAll("button");
const close = document.getElementById("close");
const modal = document.getElementById("modal");
btns.forEach((btn) => {
btn.addEventListener("click", () => {
if (btn.getAttribute("data-modal") === 'true') {
modal.showModal(); // :modalとして分類される
} else {
modal.show(); // :modalとして分類されない
}
});
})
close.addEventListener("click", () => {
modal.close();
});
modal.addEventListener("click", (e) => {
if (e.target === modal) modal.close();
});
CSS (SCSS)
showModalメゾットを使用すると擬似要素の ::backdrop
が自動的に付与されるため、cssを下記にしました。
通常のパターンでは擬似要素の ::before
で表現しています。
※backdrop擬似要素についてはこちら
.modal {
display: none;
place-content: center;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
&[open] { // dialogタグを使用するとモーダルが開いたときにopenが付与されます
display: grid;
}
&[open]:modal { // showModalメゾットを使用してモーダルを表示
background-color: transparent;
&::backdrop { // showModalメゾットを使用すると自動的に生成
background-color: rgba(0, 0, 0, 0.7);
}
}
&[open]:not(:modal) { // showModalメゾットを使用しないパターン
&::before {
background-color: #46e678;
position: absolute;
content: "";
width: 100%;
height: 100%;
left: 0;
top: 0;
}
}
}
デモ
2022年9月現在では新しいバージョンのモダンブラウザで対応可能のようです。
":modal" | Can I use... Support tables for HTML5, CSS3, etc
:is()
:is()
はセレクタのリストを引数として、セレクタのいずれかと一致する要素にスタイルを適応させます。
例えば、複数の要素に同じスタイルを適応させる場合、対象の要素が多いとcssの記述が増えてしまいますが、:is()
を使用することでコードを短く書くことが可能です。
section h1, section h2, section h3, section h4, section h5, section h6,
article h1, article h2, article h3, article h4, article h5, article h6,
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6,
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
color: #BADA55;
}
上記のように指定が多い場合でも、以下のようにスマートにまとめることができます。
:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
color: #BADA55;
}
デモサイトを作成したので確認してみてください。
HTML・CSSは以下になります。
HTML
<main>
<h1>h1タグが入ります。親要素にarticle,section,asideが無いため文字色はそのままです。</h1>
<h2>h2タグが入ります。親要素にarticle,section,asideが無いため文字色はそのままです。</h2>
<p>pタグが入ります。親要素にarticle,section,asideが無いため文字が太いままです。</p>
<section>
<h2>h2タグが入ります。sectionタグ内のh2タグなので文字色が変わります。</h2>
<p>pタグが入ります。sectionタグ内でh1〜h6タグ"以外"の要素のため文字が細くなります。</p>
</section>
<article>
<p>pタグが入ります。articleタグ内でh1〜h6タグ"以外"の要素のため文字が細くなります。</p>
<section>
<h2>h2タグが入ります。article,sectionタグ内のh2タグなので文字色が変わります。</h2>
<p>pタグが入ります。article,sectionタグ内でh1〜h6タグ"以外"の要素のため文字が細くなります。</p>
</section>
<section>
<h2>h2タグが入ります。article,sectionタグ内のh2タグなので文字色が変わります。</h2>
<p>pタグが入ります。article,sectionタグ内でh1〜h6タグ"以外"の要素のため文字が細くなります。</p>
</section>
</article>
</main>
CSS
:not()
に:is()
を入れて指定すると、他の擬似クラスと同様に指定内容を逆転させることが可能です。
article {
background-color: #939597;
padding: 40px;
}
section {
padding: 40px;
margin: 40px 0;
background-color: #F5DF4D;
}
/* article,section,aside内のh1〜h6タグのcss変更; */
:is(section, article, aside) :is(h1, h2, h3, h4, h5, h6) {
color: #df703d;
}
/* :is()を使用しない書き方
section h1,section h2,section h3,section h4,section h5,section h6,
article h1,article h2,article h3,article h4,article h5,article h6{
font-family: cursive;
color: #df703d;
}
*/
/* article,section,aside内のh1〜h6タグ"以外"のcss変更 */
article,section,aside:not(:is(h1, h2, h3, h4, h5, h6)) {
font-weight: 400;
}
/* :is()を使用しない書き方
section:not(h1,h2,h3,h4,h5,h6),article:not(h1,h2,h3,h4,h5,h6),aside:not(h1,h2,h3,h4,h5,h6){
font-weight: 400;
} */
デモ
ほとんどのモダンブラウザで使用できるようです。
:where()
:where()
はカッコ内の複数のセレクターに対しスタイルを指定することが可能で、:is()
とほぼ同じ機能があります。
詳細度が0で優先順位が一番低くなるため、詳細度を低く保っておき、スタイルを上書きしやすくしたいときに便利です。
HTML・CSSは以下になります。
HTML
html構造が同じsection要素が4つあり、class名が3種類あります。
またolタグにclass名がついてるものとついてないものがあります。
<section class="hogehoge">
<h2>First list no class</h2>
<ol>
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</section>
<section class="hogehoge">
<h2>Second list with class</h2>
<ol class="second-list">
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</section>
<section class="test">
<h2>Third list with class</h2>
<ol class="third-list">
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</section>
<section class="sample">
<h2>Fourth list with class</h2>
<ol class="third-list">
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</section>
CSS
②では:where()
で各class名を囲っているため、一番詳細度が低いです。
①では.hogehoge
の後の要素に:where()
で囲ってるclass名があるため、olタグに対してのcss指定より詳細度が高くなります。
/* ②より詳細度が高いが、①より低いため「Second list with class」にはcssが効かない */
ol {
list-style-type: decimal;
}
/* ① .hogehogeの子要素内のolタグにclassある場合スタイルを変更 */
.hogehoge :where(ol[class]) {
color: #939597;
list-style-type: none;
}
/* ② .testもしくは.sampleの子要素内のolタグにclassある場合スタイルを変更 */
:where(.test,.sample) :where(ol[class]) {
color: #F5DF4D;
list-style-type: none;
}
デモ
ほとんどのモダンブラウザで使用できるようです。
複数のcssファイルを読み込んでる時でcssを上書きする必要がある場合、より高い詳細度で上書きするか、諦めて!important
を使用する...みたいな選択肢になるかと思います。(基本前者かと思いますが)
:where()
を使用することで詳細度を0にできるので、上書きが楽になりますね。
ちょうど先日実装した案件で使えそうでした...もっと早く知っていれば...
終わりに
いかがでしたでしょうか?
まだサポートされていないブラウザもありますが、日々更新されているのでチェックしてから実務で使用していただけたらと思います...!
個人的には:has()がとっても便利だったので、デモを作りながら ニヤニヤ 感動してました。
ちなみに今回使用した色は、2021年のトレンドカラーのイエロー(イルミネイティング)とグレー(アルティメットグレイ)です。
それではまた!
参考
https://developer.mozilla.org/ja/docs/Web/CSS/:has
https://developer.mozilla.org/ja/docs/Web/CSS/:is
https://developer.mozilla.org/en-US/docs/Web/CSS/:where
https://coliss.com/articles/build-websites/operation/css/modal-css-pseudo-class.html