✍️

border-radiusの内側にバリエーションがあるデザインの実装

2022/10/23に公開約3,600字

タイトルで何を言っているのか分かりづらいですが、要は次のようなものを実装するとします。

角丸枠に2通りの背景があるデザイン。直感的にデザインの構造を受け入れると「角丸枠の中に、2色に塗られた四角がある」と認識し、HTML+CSSに反映しようとする方も多いでしょう。

しかしその方法は失敗です。初めに正解を出すと以下のようなコードになります。

<div class="Tag">
  <span class="Tag__left"></span>
  <span class="Tag__right"></span>
</div>
.Tag {
  --border: 3px solid black;
  --radii: 10px;

  display: inline-flex;
  width: 160px;
  height: 32px;
}

.Tag__left,
.Tag__right {
  width: 50%;
  border: var(--border);
}

.Tag__left {
  background-color: lightskyblue;
  border-right: 0;
  border-top-left-radius: var(--radii);
  border-bottom-left-radius: var(--radii);
}

.Tag__right {
  background-color: lightgreen;
  border-left: 0;
  border-top-right-radius: var(--radii);
  border-bottom-right-radius: var(--radii);
}

これには慣れていないとハマりそうなNG例が多々あるので、次に紹介していきます。(筆者もハマりました)
なおHTML構造は以下すべて同じなので、CSSのコードだけを記載します。

ダメなパターン

その1: 外を角丸にして解決

まずは外側と内側に分けて、外側に角丸を適用すればOKだと考えます。

.Tag1 {
  --border: 3px solid black;
  --radii: 10px;

  display: inline-flex;
  width: 160px;
  height: 32px;
  border: var(--border);
  border-radius: var(--radii);
}

.Tag1__left,
.Tag1__right {
  width: 50%;
}

.Tag1__left {
  background-color: lightskyblue;
}

.Tag1__right {
  background-color: lightgreen;
}

しかし仕様として内側へ角丸は継承されません。 このため完成には程遠い状態です。

その2: overflow-hidden

「その1」ではみ出た部分をカットすれば良いので、次にoverflow-hiddenを追加すれば良さそうです。

.Tag2 {
  --border: 3px solid black;
  --radii: 10px;

  display: inline-flex;
  width: 160px;
  height: 32px;
  overflow: hidden;
  border: var(--border);
  border-radius: var(--radii);
}

.Tag2__left,
.Tag2__right {
  width: 50%;
}

.Tag2__left {
  background-color: lightskyblue;
}

.Tag2__right {
  background-color: lightgreen;
}

適用すると前よりは状況が緩和されました。

...しかし、ちょっとした違和感がまだあるように思えます。(モニタによっては確かめられないかもしれません)
念のために拡大してみると空白がスカスカと空いています。

実のところなぜこのメカニズムなのかは分からないのですが、要するにこの解決策もダメです。

その3: 内側も角丸にする

外側と内側が連動していないのが原因らしいので、内側も同じ角丸を適用してみます。

.Tag3 {
  --border: 3px solid black;
  --radii: 10px;

  display: inline-flex;
  width: 160px;
  height: 32px;
  overflow: hidden;
  border: var(--border);
  border-radius: var(--radii);
}

.Tag3__left,
.Tag3__right {
  width: 50%;
}

.Tag3__left {
  background-color: lightskyblue;
  border-top-left-radius: var(--radii);
  border-bottom-left-radius: var(--radii);
}

.Tag3__right {
  background-color: lightgreen;
  border-top-right-radius: var(--radii);
  border-bottom-right-radius: var(--radii);
}

このパターンも当然失敗します。理由は初めの考え自体が間違っていることであり、角丸半径(border-radius)はどうなっているのかを理解すると腑に落ちます。

参考リンク: http://webcre8.jp/think/design-rounded-corner.html

正解: 並列の要素を繋ぎ合わせる

外側と内側に分けるという前提を止めて、(Uの字型の)角丸付き要素が並列に合体している構造を組むと成功します。似たようなUIの大半はこれで実装できると思います。

ここで敢えて冒頭のCSSを見返してみましょう。

.Tag {
  --border: 3px solid black;
  --radii: 10px;

  display: inline-flex;
  width: 160px;
  height: 32px;
}

.Tag__left,
.Tag__right {
  width: 50%;
  border: var(--border);
}

.Tag__left {
  background-color: lightskyblue;
  border-right: 0;
  border-top-left-radius: var(--radii);
  border-bottom-left-radius: var(--radii);
}

.Tag__right {
  background-color: lightgreen;
  border-left: 0;
  border-top-right-radius: var(--radii);
  border-bottom-right-radius: var(--radii);
}

教訓

マークアップは時により直感に反する。迷ったら挙動を確かめよう。

Discussion

ログインするとコメントできます