CSS でアウトラインのあるフキダシのしっぽを疑似要素で手軽に作る方法

IE11 の対応はそろそろ不要であることも多くなってきていると思いますので、三角形は clip-path で作るのがおすすめです。
2021.08.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

アウトラインのあるフシダシ(balloon)を作る方法はいくつかあります。ここでは疑似要素を使って作ってみます。

ここではさらに条件として、背景色が既知ではないことを前提としています。これは以下の画像での赤い部分が transparent として指定されている、あるいはそもそも存在していないかのどちらかであることを意味します。

フキダシのしっぽの背景が赤い

実際に作った実際の結果とそのリポジトリは以下の URL になります。

3つのフキダシサンプル

基本となる TSX は以下になります。Tailwind CSS を使っています。

<div
  className={`
    ${classnames(
      "relative",
      "w-min",
      "bg-blue-200",
      "border",
      "border-blue-500",
      "p-4",
      "rounded-xl"
    )}
    ${style.balloon}
  `}
/>

解説にでてくる CSS はすべて style.balloon で指定されていることが前提となっています。

border でつくる

昔からよく知られている方法で、多くのブラウザで(IE11 でも)問題なく表示されます。

三角形のジェネレータなどで検索してでてくるものは、今でもこの方法であることが多いです。

.balloon::before {
  content: "";
  border-width: 6px 8px 6px 0;
  border-color: transparent theme("colors.blue.500") transparent transparent;
  transform: translate(-9px, -50%);
  @apply absolute top-1/2 left-0 w-0 h-0 border-solid;
}

.balloon::after {
  content: "";
  border-width: 6px 8px 6px 0;
  border-color: transparent theme("colors.blue.200") transparent transparent;
  transform: translate(-8px, -50%);
  @apply absolute top-1/2 left-0 w-0 h-0 border-solid;
}

なぜ border が三角形になるのかは、以下のような指定をして実際に見てみることがわかりやすいです。

.example {
  width: 0;
  height: 0;
  border-top: 20px solid red;
  border-right: 20px solid blue;
  border-bottom: 20px solid yellow;
  border-left: 20px solid green;

これは次のような表示になります。

borderを4箇所色違いで指定。上から時計回りで赤、青、黄、緑

今回のフキダシでは blue 以外を transparent で指定すると、しっぽ部分の三角形として使用できるというわけです。

アウトラインは以降すべて共通の方法になりますが、同じ三角形を作成して左方向に 1px ずらすことでアウトラインがひかれているように見せかけています。1px よりも太いアウトラインにしたい場合には、線となる側の三角形のサイズを全体的に大きくする必要があります。

clip-path でつくる

IE11 の対応が不要であれば、clip-pathpolygon で作ることができます。

.balloon::before {
  content: "";
  clip-path: polygon(0 50%, 100% 0, 100% 100%);
  width: 8px;
  height: 12px;
  transform: translate(-9px, -50%);
  @apply absolute top-1/2 left-0 bg-blue-500;
}

.balloon::after {
  content: "";
  clip-path: polygon(0 50%, 100% 0, 100% 100%);
  width: 8px;
  height: 12px;
  transform: translate(-8px, -50%);
  @apply absolute top-1/2 left-0 bg-blue-200;
}

形の変形もしやすくサイズの指定もしやすいのでおすすめです。

指定しやすいといっても三角形で少し任意の角度をつけたいとなると慣れるまで簡単ではないので、CSS clip-path maker のようなサイトで確認する、あるいは Firefox のシェイプパスエディターが便利です。

Firefox のシェイプパスエディター

開発者ツールで赤枠の図形を選択すると図形を変形できます。

Firefox のシェイプパスエディターで変形する様子

番外編: conic-gradient で作る

IE11 も対応しておらず、あまり実用性のある方法ではありませんが、background-imageconic-gradient を使って作ることもできます。

.balloon::before {
  content: "";
  width: 16px;
  height: 12px;
  transform: translate(-17px, -50%);
  background-image: conic-gradient(
    transparent 0.9272952180016122rad,
    theme("colors.blue.500") 0,
    theme("colors.blue.500") 2.214297435588181rad,
    transparent 0
  );
  @apply absolute top-1/2 left-0;
}

.balloon::after {
  content: "";
  width: 16px;
  height: 12px;
  transform: translate(-16px, -50%);
  background-image: conic-gradient(
    transparent 0.9272952180016122rad,
    theme("colors.blue.200") 0,
    theme("colors.blue.200") 2.214297435588181rad,
    transparent 0
  );
  @apply absolute top-1/2 left-0;
}

ラジアンの計算が面倒で、今回の場合は底辺が 12px で高さは 8px となるので JavaScript で計算するのであれば以下のように求めることができます。

  • 1 回目に指定するラジアン: Math.atan2(8, 6)
  • 2 回目に指定するラジアン: Math.PI - Math.atan2(8, 6)

計算が面倒というだけでなく、斜辺の部分がギザギザになってしまっているのが気になります(ラジアンが 0 で指定されている場所をうまく調節できれば回避はできますが……)。

まとめ

IE11 の対応はそろそろ不要であることも多くなってきていると思いますので、三角形は clip-path で作るのがおすすめです。また確認ツールとしては Firefox のシェイプパスエディター が便利です。