CSSでレスポンシブ対応のボタンやグリッドに使える六角形

この記事は CSS Advent Calendar 2017 21日目の記事です。2014〜2015年くらいに流行った 六角形デザイン をCSSだけで作ってみます。ほぼすべてのブラウザで使用可能な transform: rotate() を使って実装します。

CSSで六角形を作成

CSSで六角形を作るには主に2つ方法があり、どちらも 3つの長方形を回転させて重ねる 方法です。①③は 外側でぴったり重なる ようになっていて、②④は 3つの長方形を重ねた内側 に六角形ができています。レスポンシブに対応させるため、1つの長方形の アスペクト比 を書き込んでおきました。

この2種類の方法の違いはなにかというと、①③の場合は 六角形のボーダー を作る際に向いています。長方形の 左右 に線をつければ簡単に六角形の枠ができます。一方、②④は 画像を六角形内 に表示したい際に便利です。

他にも、clip-path を使った方法もありますが、対応ブラウザがかなり限られてしまうため使わないことにしました。

③の六角形の作成

上の図で示したように、六角形は 2種類 ありますが、今回は 上下が平らな六角形 を作成していきたいと思います。片方の仕組みがわかればどちらも実装することができると思います。

先ほども説明したように、③の六角形は 枠線向き となります。

1つ目の長方形を作成


<div class="hexagon"></div>

.hexagon {
  width: 110px;
  border: 1px solid #1699cb;
}
.hexagon::before {
  display: block;
  padding-top: 173.205080757%;  /*  3 / √3 x 100  */
  content: '';
}

アスペクト比を固定 するテクニックを使って長方形の縦横比を一定にしています。

2つ目の長方形を作成


<div class="hexagon">
  <div class="hexagon__inner-1"></div>
</div>

.hexagon {
  position: relative;
  width: 110px;
  border: 1px solid #1699cb;
}
.hexagon::before {
  display: block;
  padding-top: 173.205080757%;  /*  3 / √3 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 1px solid #cb163f;
  transform: rotate(120deg);
}

3つ目の長方形を作成


<div class="hexagon">
  <div class="hexagon__inner-1"></div>
  <div class="hexagon__inner-2"></div>
</div>

.hexagon {
  position: relative;
  width: 110px;
  border: 1px solid #1699cb;
}
.hexagon::before {
  display: block;
  padding-top: 173.205080757%;  /*  3 / √3 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 1px solid #cb163f;
  transform: rotate(120deg);
}
.hexagon__inner-2 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 1px solid #1bc13e;
  transform: rotate(-120deg);
}

枠線だけにする


<div class="hexagon">
  <div class="hexagon__inner-1"></div>
  <div class="hexagon__inner-2"></div>
  <div class="hexagon__inner-3"></div>
</div>

.hexagon {
  position: relative;
  width: 100px;
}
.hexagon::before {
  display: block;
  padding-top: 173.205080757%;  /* 3 / √3 * 100 */
  content: '';
}
.hexagon__inner-1, .hexagon__inner-2, .hexagon__inner-3 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.hexagon__inner-2 {
  transform: rotate(120deg);
}
.hexagon__inner-3 {
  transform: rotate(-120deg);
}
.hexagon__inner-1::before, .hexagon__inner-1::after,
.hexagon__inner-2::before, .hexagon__inner-2::after,
.hexagon__inner-3::before, .hexagon__inner-3::after {
  position: absolute;
  left: 0;
  right: 0;
  height: 5px;
  content: '';
  background-color: #1699cb;
}
.hexagon__inner-1::before, .hexagon__inner-2::before, .hexagon__inner-3::before {
  top: 0;
}
.hexagon__inner-1::after, .hexagon__inner-2::after, .hexagon__inner-3::after {
  bottom: 0;
}

④の六角形の作成

1つ目の長方形を作成


<div class="hexagon"></div>

.hexagon {
  width: 150px;
  box-shadow: 0 0 0 1px #1699cb inset;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}

2つ目の長方形を作成


<div class="hexagon">
  <div class="hexagon__inner-1"></div>
</div>

.hexagon {
  width: 150px;
  box-shadow: 0 0 0 1px #1699cb inset;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #cb163f inset;
  transform: rotate(60deg);
}

3つ目の長方形を作成


<div class="hexagon">
  <div class="hexagon__inner-1">
    <div class="hexagon__inner-2"></div>
  </div>
</div>

.hexagon {
  width: 150px;
  box-shadow: 0 0 0 1px #1699cb inset;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #cb163f inset;
  transform: rotate(60deg);
}
.hexagon__inner-2 {
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #1bc13e inset;
  transform: rotate(60deg);
}

回転させた分元に戻す


<div class="hexagon">
  <div class="hexagon__inner-1">
    <div class="hexagon__inner-2">
      <div class="hexagon__inner-3"></div>
    </div>
  </div>
</div>

.hexagon {
  width: 150px;
  box-shadow: 0 0 0 1px #1699cb inset;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #cb163f inset;
  transform: rotate(60deg);
}
.hexagon__inner-2 {
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #1bc13e inset;
  transform: rotate(60deg);
}
.hexagon__inner-3 {
  width: 100%;
  height: 100%;
  transform: rotate(-120deg);
}

回転させた分(120deg)戻さないと中に設置する画像が回転してしまったままになります。

overflow:hidden ではみ出した部分を隠す


<div class="hexagon">
  <div class="hexagon__inner-1">
    <div class="hexagon__inner-2">
      <div class="hexagon__inner-3"></div>
    </div>
  </div>
</div>

.hexagon {
  width: 150px;
  box-shadow: 0 0 0 1px #1699cb inset;
  overflow: hidden;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #cb163f inset;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-2 {
  width: 100%;
  height: 100%;
  box-shadow: 0 0 0 1px #1bc13e inset;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-3 {
  width: 100%;
  height: 100%;
  transform: rotate(-120deg);
}

はみ出した部分を隠せば六角形ができます。

背景に画像を配置


<div class="hexagon">
  <div class="hexagon__inner-1">
    <div class="hexagon__inner-2">
      <div class="hexagon__inner-3">
        <div class="hexagon__inner-image"></div>
      </div>
    </div>
  </div>
</div>

.hexagon {
  position: relative;
  width: 150px;
  overflow: hidden;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;  /*  2√3 / 4 x 100  */
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-2 {
  width: 100%;
  height: 100%;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-3 {
  width: 100%;
  height: 100%;
  transform: rotate(-120deg);
}
.hexagon__inner-image {
  width: 100%;
  height: 100%;
  background: url(https://spyweb.media/wp-content/uploads/2017/12/1513521415.jpg) center / cover no-repeat;
}

こんな感じで 背景画像 などを配置するのに向いています。

応用例

六角形を使って グリッド を作ってみました。

位置関係の計算に使う はこんな感じになっています。


<div class="grid">
  <div class="grid__item">
    <div class="grid__gutter">
      <div class="hexagon">
        <div class="hexagon__inner-1">
          <div class="hexagon__inner-2">
            <div class="hexagon__inner-3">
              <div class="hexagon__inner-image"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="grid__item">
    <div class="grid__gutter">
      <div class="hexagon">
        <div class="hexagon__inner-1">
          <div class="hexagon__inner-2">
            <div class="hexagon__inner-3">
              <div class="hexagon__inner-image"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  ...
</div>

*, ::before, ::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.grid {
  display: flex;
  flex-wrap: wrap;
  margin-left: calc((100% * 2 / (4 * 5 + 2 * 4)) * -1 - 20px);
}
.grid__item {
  display: inline-block;
  width: 20%;
}
.grid__gutter {
  padding-left: calc((100% / 3) + 20px);
}
.grid__item:nth-child(9n+1) {
  margin-left: calc((20% - 40px) / 2 + 20px);
}
.grid__item:nth-child(9n+5) .hexagon, .grid__item:nth-child(9n+6) .hexagon, .grid__item:nth-child(9n+7) .hexagon, .grid__item:nth-child(9n+8) .hexagon, .grid__item:nth-child(9n+9) .hexagon {
  margin-top: calc(10px - 43.3012701892%);
}
.grid__item:nth-child(n+10) .hexagon {
  margin-top: calc(10px - 43.3012701892%);
}
.hexagon {
  position: relative;
  width: 100%;
  overflow: hidden;
}
.hexagon::before {
  display: block;
  padding-top: 86.602540378%;
  content: '';
}
.hexagon__inner-1 {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-2 {
  width: 100%;
  height: 100%;
  overflow: hidden;
  transform: rotate(60deg);
}
.hexagon__inner-3 {
  width: 100%;
  height: 100%;
  transform: rotate(-120deg);
}
.hexagon__inner-image {
  width: 100%;
  height: 100%;
  background: url(https://spyweb.media/wp-content/uploads/2017/12/1513521415.jpg) center / cover no-repeat;
}

複雑な計算式になってしまいますが、こんな感じで六角形のグリッドを作ることもできます。それぞれの計算式については解説しませんが、 比を使って相対的に指定 することでレスポンシブに対応させています。

応用例としてグリッドを挙げましたが、ボタン などに使うのもおしゃれでいいと思います。

もしかしたら、六角形グリッドを使いたい人もいるかもしれないので、現在開発中のSCSSフレームワークに @mixin として組みこもうかなと思っています。