CSSでいい感じに相対位置を調整する

4 min read読了の目安(約3600字

CSSで相対的な位置を調整するのって結構めんどくさいですよね!
意外と実践的なサンプルは少なかったりするので、今回は実際にCSSによる位置合わせとその時のコツを書きたいと思います。

作りたいもの

写真の上に吹き出しの線と説明文をコーディングしたいと思います。

このとき下記2点を考慮します。
・window幅に合わせて画像は伸縮するけど、線と説明文の位置がずれないようにしたい
・ある一定サイズ以下になったら画像サイズは固定になる

できあがったものとしては↓のようになります。


それでは実装していきます!(記事中では端折ってる箇所があるので、完成版はサンプルコードを見てください)
サンプルコード

https://github.com/an-0305/css-sample

実装してみる

その1

下記キャプチャの部分を実装していきます。

一旦、縦線の部分は無視して、横線とテキストの部分を実装していきます。

index.html

<div class="wrapper">
  <img src="./img/cat.jpg" alt="猫" class="cat-img">
  <div class="features">
    <div class="head">特徴</div>
    <div class="description">縞模様でしっぽが長め</div>
  </div>
</div>

main.css

.wrapper {
  position: relative;
  width: 100%;
  min-width: 1200px;
}
.cat-img {
  width: 100%;
}
.features {
  position: absolute;
  bottom: 0;
  right: 300px;
  width: 400px
}
.head {
  padding-bottom: 10px;
  margin-bottom: 10px;
  border-bottom: 1px solid #333;
  font-size: 20px;
  font-weight: bold;
}

今回は最小幅を1200pxに設定します。
画面幅に合わせた動的な位置調整が必要となりますが、最初からやろうとするとややこしくなるのでまずは画面幅を1200pxにして、固定値で位置を調整します。

横線は、下記のようにdivを使って表現するのでなく、

<div class="line"></div>

.line {
  width: 400px;
  heigh: 1px;
  background-color: #333
}

.headに対するborderと考えて実装するとシンプルに実装できます。
もしdivを使って実装するとdivに対しても位置調整が必要になるのでより複雑になります。

その2

テキストと横線ができたので次は縦線を実装します。
縦線はdivを使わないと実装できないのでdivで実装して位置を調整していきます。

 <div class="features">
   <div class="head">特徴</div>
   <div class="description">縞模様でしっぽが長め</div>
   <div class="line"></div>
 </div>

ここでポイントになるのが、縦線を作るdiv要素を.features直下に置くことです。
これにより.lineの親は.featuresになり、縦線の横位置をright: 0で簡単に指定することができます。
もし.lineを.featuresの外においてしまうと、.featuresとの位置関係を調整する必要がでてきて、複雑になります。

縦線の要素ににスタイルを当てます。

.features .line {
  position: absolute;
  top: 40px;
  right: 0;
  width: 1px;
  height: 120px;
  background-color: #333;
  transform: translateY(-120px);
}

top: 40pxだけだと下記の状態になり、

transform: translateY(-120px)を指定することで縦線の長さ分だけ上に縦線を移動させ、正しい位置に合わせます。

transformを使わずにtopだけで縦線の位置を調整したらいいと思うかもしれません。しかしtopだけで揃えようとすると、後ほど画面幅が可変になったときtopの値も比率で計算しなければならず複雑になるので、topの値は固定にして棒の長さ分だけずらすという考え方で実装します。

その3

ここまでの実装で画面幅が1200pxのときの線とテキストの位置調整ができていると思います。
次は画面幅が1200pxより大きくなったときの位置を調整していきたいと思います。

calcを使い、1200pxの幅に対して対象の要素がどれぐらいの幅を占めるかという考え方で比率を求めていきます。

.features {
  position: absolute;
  bottom: 0;
  right: calc(100% * 300 / 1200);
  width: calc(100% * 400 / 1200);
}

.features .line {
  position: absolute;
  top: 40px;
  right: 0;
  width: 1px;
  height: calc(100vw * 120 / 1200);
  background-color: #333;
  transform: translateY(calc(100vw * 120 / 1200 * -1));
}

その4

最後にwindow幅が1200pxより小さいときを考えたいと思います。
1200pxを切ると画像の幅は1200pxで固定ですが、今の実装だと画面横幅に対する比率で縦線の高さを指定しているので、画面横幅を縮めていくと縦線がどこまでも短くなります。
そのため、縦線には最小の高さを指定します。(このときmedia-queryを利用して、横幅が1200pxを切った場合の定義を追加して、縦線を上方向にtranslateする値を縦線の最小の高さと同じ値で固定します。)

.features .line {
  position: absolute;
  top: 40px;
  right: 0;
  width: 1px;
  height: calc(100vw * 120 / 1200);
  min-height: 120px;
  background-color: #333;
  transform: translateY(calc(100vw * 120 / 1200 * -1));
}

@media screen and (max-width: 1199px) {
  .features .line {
    transform: translateY(-120px);
  }
}

以上で完成です🙌

まとめ

位置を指定するときはすべての値を相対値で調整するのではなく、固定値で指定できるところを見つけて相対指定する場所がなるべく少なくなるようにすると考えやすくなります!