🫥

CSSの疑似要素で逆角丸 with Tailwind

2024/10/19に公開

こんな逆角丸作りたい時ありますよね

これを余計なDOMを増やさず、Tailwindだけで実現する方法を紹介します
※Tailwindは入っている前提になります

結論

<div>
  <div
    class="relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500 before:absolute before:bottom-0 before:left-full before:h-2 before:w-2 before:bg-green-500 after:absolute after:bottom-0 after:left-full after:h-2 after:w-2 after:rounded-bl-lg after:bg-white"
  >
    <div class="truncate px-3 py-1 font-bold text-white">
      タブ名
    </div>
  </div>
  <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
    コンテンツ
  </div>
</div>

解説

まずは逆角丸なしのシンプルなタブデザインを実装

幅を狭めるとこうなるイメージです

<div>
  <div class="w-fit max-w-[calc(100%-8px)] rounded-t-lg bg-green-500">
    <div class="px-3 py-1 font-bold text-white">
      タブ名
    </div>
  </div>
  <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
    コンテンツ
  </div>
</div>

なんとなくtruncate

タブ名は改行したくない

ってときはこうですね

 <div>
   <div class="w-fit max-w-[calc(100%-8px)] rounded-t-lg bg-green-500">
-    <div class="px-3 py-1 font-bold text-white">
+    <div class="truncate px-3 py-1 font-bold text-white">
       タブ名
     </div>
   </div>
   <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
     コンテンツ
   </div>
 </div>

逆角丸のための背景を追加

まずは背景を追加

疑似要素の理解のため、あえてDOMを追加しています

 <div>
-  <div class="w-fit max-w-[calc(100%-8px)] rounded-t-lg bg-green-500">
+  <div class="relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500">
+    <div class="absolute bottom-0 left-full h-2 w-2 bg-green-500"></div>
     <div class="truncate px-3 py-1 font-bold text-white">
       タブ名
     </div>
   </div>
   <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
     コンテンツ
   </div>
 </div>

逆角丸にする

先ほどの背景に白い角丸を重ねるイメージ
背景色が白じゃない時がちょいと面倒

今回もいったん要素を追加

 <div>
   <div class="relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500">
     <div class="absolute bottom-0 left-full h-2 w-2 bg-green-500"></div>
     <div class="truncate px-3 py-1 font-bold text-white">
       タブ名
     </div>
+    <div class="absolute bottom-0 left-full h-2 w-2 rounded-bl-lg bg-white"></div>
   </div>
   <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
     コンテンツ
   </div>
 </div>

疑似要素化

見た目は変わりませんがHTML上の要素数が減ります
疑似要素はその要素内の先頭、末尾に要素を一つ追加するイメージなので、その要素をrelativeにすれば好きな位置にいろんなものを配置できますね
だから末尾に「円」って入れたりもできますし、先頭に「¥」を追加したりもできるわけですね

 <div>
-  <div class="relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500">
+  <div
+    class="relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500 before:absolute before:bottom-0 before:left-full before:h-2 before:w-2 before:bg-green-500 after:absolute after:bottom-0 after:left-full after:h-2 after:w-2 after:rounded-bl-lg after:bg-white"
+  >
-    <div class="absolute bottom-0 left-full h-2 w-2 bg-green-500"></div>
     <div class="truncate px-3 py-1 font-bold text-white">
       タブ名
     </div>
-    <div class="absolute bottom-0 left-full h-2 w-2 rounded-bl-lg bg-white"></div>
   </div>
   <div class="rounded-b-lg rounded-tr-lg border border-green-500 p-3">
     コンテンツ
   </div>
 </div>

あとがき

Tailwind使うとどうしたってclass属性が長くなる
今回の最も長い行で270字近い
フレームワークを使うならこの逆角丸だけコンポーネントに切り出せば1行100字前後になるんだろうか?
と思ったが210字程度にしかならぬ。。。
フレームワークなら大抵クラスを配列で渡せるだろうからbeforeとafterで改行すれば110字前後
ここらへんが落としどころか。。。

<template>
  <div
    :class="[
        'relative w-fit max-w-[calc(100%-16px)] rounded-t-lg bg-green-500',
        'before:absolute before:bottom-0 before:left-full before:h-2 before:w-2 before:bg-green-500',
        'after:absolute after:bottom-0 after:left-full after:h-2 after:w-2 after:rounded-bl-lg after:bg-white',
    ]"
  ></div>
</template>
株式会社find | 落とし物クラウド

Discussion