アクティブなメニューの外側の角を丸くする CSS
はじめに
問題です。下の画像のようなメニューを作るには、どのような CSS を指定すればいいでしょうか?
悩みどころは、アクティブなメニューの外側の角を丸くすることだと思います。
このような外側の角が丸いアクティブなメニューを作る CSS を紹介します。使用する CSS プロパティは box-shadow
です。メニューの他に、タブにも使えると思います。
デモ
実際のデモをご覧ください。
デモの HTML です。アクティブなメニューの class に active
が付くものとします。
<ul class="list">
<li><a class="link" href="...">メニュー</a></li>
<li><a class="link active" href="...">メニュー</a></li>
<li><a class="link" href="...">メニュー</a></li>
<li><a class="link" href="...">メニュー</a></li>
</ul>
そして、CSS です。ダークモードに対応しているとします。ポイントは、.active::before
と .active::after
に指定した box-shadow
です。
html {
--bg-color: #fff;
--text-color: #212121;
--menu-bg-color: #f5df4d;
--menu-text-color: #434343;
--pseudo-size: 40px;
}
@media (prefers-color-scheme: dark) {
html {
--bg-color: #121212;
--text-color: #ddd;
}
}
body {
background: var(--bg-color);
}
.list {
background: var(--menu-bg-color);
border-radius: 16px;
list-style: none;
padding: 24px 0;
width: min(360px, 70vw);
}
.link {
border-radius: 50px;
color: var(--menu-text-color);
display: block;
font-weight: 500;
margin: 8px 24px;
padding: 24px;
position: relative;
text-decoration: none;
transition: background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 1;
}
.active {
background: var(--bg-color);
border-radius: 50px 0 0 50px;
color: var(--text-color);
margin-right: 0;
z-index: 0;
}
.active::before,
.active::after {
background: var(--menu-bg-color);
box-shadow: calc(var(--pseudo-size) / 2) 0 var(--bg-color);
content: '';
height: var(--pseudo-size);
pointer-events: none;
position: absolute;
right: 0;
width: var(--pseudo-size);
}
.active::before {
border-bottom-right-radius: 50%;
top: calc(var(--pseudo-size) * -1);
}
.active::after {
border-top-right-radius: 50%;
bottom: calc(var(--pseudo-size) * -1);
}
/* :hover と :focus の指定 */
.link:hover {
background: #f1c728;
color: var(--menu-text-color);
}
.link:focus {
background: #eeb022;
color: var(--menu-text-color);
}
.active:hover::before,
.active:hover::after,
.active:focus::before,
.active:focus::after {
content: none;
}
解説
CSS を解説します。
このようなメニューがあるとします。
まずは、class に active
が付いているメニューの背景色を <body>
タグの背景色と同じにします。デモでは 2 番目のメニューです。この時点では、外側の角は丸くなりません。
.active {
background: var(--bg-color);
border-radius: 50px 0 0 50px;
color: var(--text-color);
margin-right: 0;
z-index: 0;
}
次に、active
が付いているメニューに ::before
と ::after
の疑似要素を追加します。まだ box-shadow
は指定していないため、外側の角は丸くなりません。
.active::before,
.active::after {
background: var(--menu-bg-color);
content: '';
height: var(--pseudo-size);
pointer-events: none;
position: absolute;
right: 0;
width: var(--pseudo-size);
}
.active::before {
border-bottom-right-radius: 50%;
top: calc(var(--pseudo-size) * -1);
}
.active::after {
border-top-right-radius: 50%;
bottom: calc(var(--pseudo-size) * -1);
}
分かりやすくするために、::before
と ::after
の疑似要素の色を赤にしてみます。現時点では、このようになっています。
最後に、::before
と ::after
の疑似要素に box-shadow
を指定します。box-shadow
の色は、<body>
タグの背景色と同じです。これで外側の角が丸くなります。
.active::before,
.active::after {
box-shadow: calc(var(--pseudo-size) / 2) 0 var(--bg-color);
}
分かりやすくするために、::before
と ::after
の疑似要素の色を赤、box-shadow
の色を#00ffff
にしてみます。
#00ffff
の部分が <body>
タグの背景色と同じため、角が丸く見えるという理屈です。
box-shadow
は、全部で 4 つの長さを指定できます。今回は、そのうちの 2 つ offset-x
と offset-y
を指定しています。
1 番目の長さに指定した calc(var(--pseudo-size) / 2)
は、offset-x
の値です。水平方向の距離を表し、正の値を指定すれば影は右方向に移動します。今回は、::before
と ::after
の疑似要素の width
の値の半分だけ右方向に移動しています。
2 番目の長さに指定した 0
は、offset-y
の値です。垂直方向の距離を表し、正の値を指定すれば影は下方向に移動します。今回は移動させたくないため、0
を指定しています。
box-shadow
の 3 番目の長さは、blur-radius
です。影のぼかしの距離を指定するものですが、今回は指定していません。指定していない場合は値は 0
となり、影はぼけません。
box-shadow
の 4 番目の長さは、spread-radius
です。影の広がりの距離を指定するものですが、今回は指定していません。指定していない場合は値は 0
となり、影の大きさは要素の大きさと同じになります。
今回は、「ぼけていない」かつ「広がっていない」影を使い、角を丸く見せています。