Instagramの各パーツをflexboxで組み立てる

  • 14
    いいね
  • 0
    コメント

社内勉強会での発表用の作品として、InstagramのアプリをWebで再現してみようと思い、HTMLとCSSとjQueryで組みました。
その中で、今回自分の中での縛りとして出来る限り横並びボックスはflexboxで組んだので、
今回はその各パーツをどのように再現したのかまとめたいと思います。

模写したページ

insta記事用画像.png

こんな感じで見た目の模写をしました。
早速それぞれどのように組んだのかのソースを書こうと思いますが、
その前に今回出現率の高いプロパティの説明を先に書きたいと思います。

よくでてくるプロパティ

justify-content

flexアイテムの配置位置の指定ができ、余白の調整ができます。
簡単に言うと水平方向の配置の指定です。

スタイル 意味
flex-start 左寄せ(縦並びにした場合は上寄せ)
flex-end 右寄せ(縦並びにした場合は下寄せ)
center 中央寄せ
space-between 横幅いっぱいで等間隔
space-around 左右に余白をあけて横幅いっぱいで等間隔

align-items

justify-contentと違ってこちらは垂直方向の配置指定になります。

スタイル 意味
flex-start 上寄せ(縦並びにした場合は左寄せ)
flex-end 下寄せ(縦並びにした場合は右寄せ)
center 中央寄せ
baseline ベースラインに揃える
stretch 高さを他のアイテムの高さに揃えて上下いっぱいにします

これらを駆使して書いていきたいと思います。

:one: ヘッダー

ポイント:最初と最後の要素を端に寄せて等間隔で並べる

作ったパーツ

1.png

HTML

<header class="header">
  <div>
    <a href="#camera" class="header-camera"><img src="dst/img/camera.png" alt="カメラ" class="header-camera-img"></a>
  </div>
  <h1>
    <a href="#post" class="header-logo is-active"><img src="dst/img/logo.png" alt="Instagram" class="header-logo-img"></a>
  </h1>
  <div>
    <a href="#mail" class="header-mail"><img src="dst/img/mail.png" alt="メール" class="header-mail-img"></a>
  </div>
</header>

sass

.header {
  height: 55px;
  display: flex;
  position: fixed;
  z-index: 2;
  width: 100%;
  justify-content: space-between;
  box-shadow: 0 2px 2px rgba(210, 210, 210, .7);
  background-color: $background-color;

  & > * {
    display: flex;
  }

  .header-container {
    padding: 15px;
  }

  .header-logo {
    display: flex;
    align-items: center;
    border-bottom: 2px solid $background-color;

    &-img {
      width: 101px;
    }
  }

  .header-camera {
    display: flex;
    align-items: center;
    padding: 0 15px;
    border-bottom: 2px solid $background-color;

    &-img {
      width: 25px;
    }
  }

  .header-mail {
    display: flex;
    align-items: center;
    padding: 0 15px;
    border-bottom: 2px solid $background-color;

    &-img {
      width: 25px;
    }
  }

  .is-active {
    border-bottom-color: $primary-color;
  }

  .header-menu-img {
    width: 23px;
    height: 20px;
  }
}

flexをつけた要素にjustify-content:space-between;を指定して一番最初と最後は端寄せにして等間隔で配置します。
今回は3つ並べたので2つ目は自動で真ん中に配置されました!きれいになった!やったー!:raised_hands:

:two: 投稿写真のヘッダー

ポイント:IDだけ長くて一番右にメニューアイコンをくっつける

作ったパーツ

2.png

HTML

<div class="post-header">
  <div class="post-icon">
    <img src="dst/img/photo/7.jpg" class="post-icon-img">
  </div>
  <div class="post-name">
    <a href="">hogehogeID</a>
  </div>
  <div class="post-menu">
    <img src="dst/img/post-menu.png" class="post-menu-img">
  </div>
</div>

sass

.post-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  margin-bottom: 10px;

  .post-icon {
    margin: 0 8px 0 15px;

    .post-icon-img {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      border: 1px solid #dbdbdb;
    }
  }

  .post-name {
    flex: 1;
  }

  .post-menu {
    padding: 0 15px;
    cursor: pointer;

    .post-menu-img {
      width: 3px;
    }
  }
}

ID名をかいている「post-name」にだけflex:1;を指定しました。
flex:1 はショートハンドで、 flex: 1 1 0; ということになります。
これによって、flexコンテナ内の余白をpost-nameだけ与えます。
※flexコンテナ内の余白をflex-growの合計数で割ってその横幅を分け与えるので、
 この指定方法だとpost-nameにflex-growの合計数(1)つまり横幅全部を与えます。

:three: 投稿写真のアクション用アイコン

ポイント:3つめまでは左寄せ、ストックアイコンだけ右寄せ

作ったパーツ

3.png

HTML

<ul class="post-action">
  <li>
    <div class="js-post-action">
      <img src="dst/img/action-heart.png" class="post-action-img">
    </div>
  </li>
  <li>
    <div>
      <img src="dst/img/action-comment.png" class="post-action-img">
    </div>
  </li>
  <li>
    <div>
      <img src="dst/img/action-mail.png" class="post-action-img">
    </div>
  </li>
  <li>
    <div class="js-post-action post-stock">
      <img src="dst/img/action-stock.png" class="post-action-img">
    </div>
  </li>
</ul>

sass

.post-action {
  width: 100%;
  display: flex;
  padding-bottom: 10px;
  margin-bottom: 10px;
  border-bottom: 1px solid #dbdbdb;
  justify-content: space-between;

  li {
    margin-right: 15px;

    &:last-child {
      flex: 1;
      text-align: right;
      margin-right: 0;
    }

    > * {
      cursor: pointer;
    }
  }

  .post-stock {
    width: 24px;
    display: inline-block;
  }

  .post-action-img {
    width: 24px;
  }
}

これも大体は :two: と同じです。
ただ :two: と違うのは、3つ目のアイコンにflex:1;をつけていると思いきや4つ目の右端のアイコンにつけています。
特に明確な理由はないのですが、意味合い的にそのほうがしっくりくるなと思ったからです。

:four: フッター

ポイント:等間隔に並べる

作ったパーツ

4.png

HTML

<div class="home-footer">
  <ul class="home-footer-menu">
    <li class="js-home-footer">
      <a class="home-footer-anchor"><img src="dst/img/home-on.png" alt="ホーム" class="home-footer-img"></a>
    </li>
    <li class="js-home-footer is-hide">
      <a class="home-footer-anchor"><img src="dst/img/search.png" alt="検索" class="home-footer-img"></a>
    </li>
    <li class="js-home-footer js-home-footer-camera is-hide">
      <a class="home-footer-anchor"><img src="dst/img/upload.png" alt="投稿" class="home-footer-img"></a>
    </li>
    <li class="js-home-footer is-hide">
      <a class="home-footer-anchor"><img src="dst/img/heart.png" alt="いいね" class="home-footer-img"></a>
    </li>
    <li class="js-home-footer is-hide">
      <a class="home-footer-anchor"><img src="dst/img/user.png" alt="マイページ" class="home-footer-img"></a
    ></li>
  </ul>
</div>

sass

.home-footer {
  height: 60px;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  box-shadow: 0 -2px 2px rgba(210, 210, 210, .7);
  background-color: $background-color;
  z-index: 3;

  .home-footer-menu {
    display: flex;
    justify-content: space-between;
    padding: 0 15px;
    height: 100%;

    li {
      display: flex;
    }
  }

  .home-footer-anchor {
    display: flex;
    align-items: center;
    padding: 15px;
  }

  .home-footer-img {
    width: 25px;
  }
}

ヘッダーも等間隔に並べていたので同じですが、こちらの方が数が多いので分かりやすいですね。
左右に余白を付けたかったのでjustify-content: space-around;にしようかと思ったのですが、
一番端に付く余白が、各アイテム間の余白の半分になるのでちょっと狭くてやめました。

今回は画像サイズが統一だったので良かったのですが、
例えば中のアイテムがテキストだったりで横幅が違う場合、flex-basisで横幅を指定しないと等間隔にならないです。ざんねんですね:cry:

:five: マイページのヘッダー

ポイント:一つ目だけ左端、あとは右寄せ

作ったパーツ

5.png

HTML

<div class="header headerMypage">
  <div class="headerMypage-name">hogehogeID</div>
  <div class="headerMypage-share headerMypage-icon">
    <img src="dst/img/share-icon.png" class="headerMypage-img">
  </div>
  <div class="headerMypage-follow headerMypage-icon">
    <a href=""><img src="dst/img/follow-icon.png" class="headerMypage-img"></a>
  </div>
  <div class="headerMypage-menu headerMypage-icon">
    <a href=""><img src="dst/img/mypage-menu-icon.png" class="headerMypage-img"></a>
  </div>
</div>

sass

.headerMypage {
  padding: 15px;
  align-items: center;

  .headerMypage-name {
    flex: 1;
  }

  .headerMypage-icon {
    padding: 0 10px;
    align-items: center;

    &.headerMypage-menu {
      padding-right: 0;
    }
  }

  .headerMypage-img {
    width: 23px;
    height: 20px;
  }
}

上にでてきたパーツとだいたい一緒です、
今回も投稿記事のヘッダーと同じくID名の部分を横幅広くすることで他の要素が右寄せになっているように見えます。

:six: マイページの切り替えタブ

ポイント:等間隔だけど左右に隙間

作ったパーツ

6.png

HTML

<ul class="mypage-post-tab">
  <li class="js-mypage-tab">
    <img src="dst/img/mypage-tile-on.png" class="mypage-tab-img">
  </li>
  <li class="js-mypage-tab">
    <img src="dst/img/mypage-column.png" class="mypage-tab-img">
  </li>
  <li class="js-mypage-tab-me">
    <img src="dst/img/mypage-me.png" class="mypage-tab-img">
  </li>
  <li class="js-mypage-tab-stock">
    <img src="dst/img/mypage-stock.png" class="mypage-tab-img">
  </li>
</ul>

sass

.mypage-post-tab {
  display: flex;
  justify-content: space-around;
  border-top: 1px solid #dbdbdb;
  border-bottom: 1px solid #dbdbdb;

  li {
    padding: 15px;
    cursor: pointer;

    .mypage-tab-img {
      width: 24px;
      height: 21px;
    }
  }
}

こちらは等間隔でspace-aroundを使っています。
こちらの場合は左右の余白が、アイテム間の余白の半分でちょうどよかったです。
space-aroundのような配置の指定ができるプロパティはなかなかないので便利ですね:v:

:seven: 投稿写真一覧

ポイント:3つで折り返し、一行の数が3つに満たない場合は左寄せ

作ったパーツ

7.png

HTML

<ul class="photo-list">
  <li>
    <a href=""><img src="dst/img/photo/30.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/29.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/28.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/27.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/25.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/24.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/22.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/20.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/19.jpg" class="photo-list-img"></a>
  </li>
  <li>
    <a href=""><img src="dst/img/photo/18.jpg" class="photo-list-img"></a>
  </li>
</ul>

sass

.photo-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;

  li {
    flex-basis: 33.3%;

    .photo-list-img {
      width: 100%;
      border: 1px solid #fff;
    }
  }
}

左寄せはjustify-content: flex-start;で指定、
flex-wrap-: wrap; ではみ出した場合折り返すように指定、
子要素のflex-basisで横幅を指定してます。(これはcalc使えばよかったですね…そうすれば4つで折り返しにしたいときも簡単です!:ok_woman:

inline-blockでも実装可能なパーツではありますが、flexを使うとこんな感じになりました!

まとめ

作品自体は他のページも作ったのですが、この2画面だけでもflexで組み立てるパーツがいくつもでてきました。
今回は発表用だったためflexのみで実装しましたが、古いブラウザやOSを考えるとなかなかflexのみでは実装できません。
ただこんなに簡単に横並びのいろいろな要素が実装できるのではやくflexが崩れるブラウザやOSは滅びないかな…とAndroid4系のバグを調査しながら思いました。

上にあげたものはjustify-contentを中心に説明しましたが、align-itemsもかなり便利なプロパティです!
今日もflexboxの普及を祈りつつねむります:relaxed: