アクティブなメニューの外側の角を丸くする 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
にしてみます。
box-shadow
の #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
となり、影の大きさは要素の大きさと同じになります。
今回は、「ぼけていない」かつ「広がっていない」影を使い、角を丸く見せています。