🙌

cssのみで表現するパララックス

2023/04/01に公開

TL;DR

  • 今回は掲題の通り、パララックスを css だけで表現するよ。
  • とはいえ開発ツールとして docker とか prettier とか sass とか使うよ
  • 今回は Mac Chrome ブラウザで動作確認したけどそれ以外は確認していないからクロスブラウザでちゃんと動くかは保証しないから苦情は受け付けないよ。 position: sticky に正常に対応しているブラウザなら大丈夫なはずだけどね。
  • 前提の説明が長すぎるので結論から見たい人は 本題 だけ見るといいと思うよ。
  • あくまで方法の一つとして紹介がてら css で遊んでただけだから随所で適当な箇所があるよ。
  • リポジトリは公開しているから適当に見てね
    parallax-sample
  • 実際のページは こちら

利用ツール

  • docker for Mac
  • sass
  • eslint
  • prettier
  • stylelint
  • nodejs 18.x

ファイル構成

├── LICENSE
├── README.md
├── docker-compose.yml
├── docs
│   ├── css
│   │   └── index.css
│   ├── favicon.ico
│   └── index.html
├── package.json
├── src
│   └── scss
│       └── index.scss
└── yarn.lock

各ファイルについて

テキスト形式ファイル

下記は見ての通り

  • LICENSE
  • README.md

docker について

localhost で http アクセスするために docker を利用するよ。
README にある通りだけど一応解説しておくと docker-compose.ymlhttpd(apache)を使って http 越しにアクセスするよ。

今回は js 使ってないから関係ないけど js を動かす場合 file:// プロトコル で 直接 local の html を表示した場合、セキュリティの関係でブラウザが js をブロックするからその対策だと思ってくれて構わないよ。

というわけで

$ docker-compose up -d

# 使い終わったら落とす
# $ docker-compose down

上記を叩いて http サーバを立ち上げるんだ。

そうすることでdocker-compose.ymlに記載したとおり

 # imageの指定だよ
image: httpd:2.4
 volumes:
  # ローカルのdocsディレクトリをdockerコンテナ内の/usr/local/apache2/htdocs/ ディレクトリと同期するよ
  - ./docs:/usr/local/apache2/htdocs/
ports:
  # ローカルの8080番ポートをコンテナ内の80番ポートに転送するよ
  - '8080:80'

こうすることで http://localhost:8080/ にアクセスすることで docs 配下のファイルにアクセスできるよ。

これでブラウザからアクセスする準備は完了だ。

npm モジュールについて

今回 npm モジュールをいくつか使っているけどこれらは docs 配下に直接 html と css を記載するだけなら本当は必要ないんだ。

ちなみに npm run コマンドyarn コマンド はほぼ同義だ。
各モジュールについて解説しよう。

  • eslint* これらは js を整形、指定した規則に従わせるツールだ(今回は js 使ってないから無視してくれて構わない)
  • npm-run-all これは npm run をワイルドカードで起動できる便利ツールだ。後で少しだけ解説するよ。
  • sass css を scss で記述するために使うよ
  • prettier 対象のファイルを整形するツールだよ。
  • stylelint* css の整形ツールだよ。

ぶっちゃけ sass 以外は整形するためのツールだからなくとも構わない。

npm-run-allpackage.jsonの scripts に記述したコマンドを一括で実行するためのツールだ。

{
  "scripts": {
    "fix:scss": "stylelint --fix src/**/*.{css,scss,sass} --config-basedir .",
    "fix:eslint": "eslint --fix .",
    "fix:prettier": "prettier --write .",
    "fix": "run-s fix:*",
    "build:sass": "yarn sass --no-source-map src/scss/:./docs/css/ && rm -rf docs/css/index.css.map",
    "watch:sass": "yarn sass --watch src/scss/:./docs/css/"
  }
}

今回 scripts には上記の様に記載してある。
これらはnpm run fix:scss と打つと

$ npm run stylelint --fix src/**/*.{css,scss,sass} --config-basedir .

と打つのと同じ意味になる。つまりはショートカットを定義しているんだ。
そして npm-run-all によってこれらのショートカットをまとめて叩くことが可能になるんだ。
例えば npm run fix とうつと

# run-s はシリアル、つまり順次実行するという意味でfix:*にマッチするスクリプトを実行する
# run-p とした場合はパラレル、つまり非同期に実行するよ。
# 個々のファイルを同時にいじるとまずいから今回は-sでシリアルに実行する
$ run-s fix:*

となる。

次に sass のコンパイルのお話だ。

$ npm run build:sass

を実行することで

$ yarn sass --no-source-map src/scss/:./docs/css/ && rm -rf docs/css/index.css.map
# yarn sass --no-source-map src/scss/:./docs/css/
# 上記でsrc/scssの中身をdocs/css/にコンパイルしている
# その上でもしソースマップが存在していた場合、
# rm -rf docs/css/index.css.map
# で削除する
$ yarn sass --watch src/scss/:./docs/css/
# これはscssをコンパイルするのは変わらないけどwatchなので変更を検知してリアルタイムで変換する
# そしてこのコマンドを実行することによってソースマップも作られる
# 開発中は watch でリアルタイム反映してリリースする時にbuildする感じの使い方をするよ。

となる。 [1]

本題

長くなったけどここからが本題
まず html だけどこんな感じ

html

<div>
  <section>
    <img src="https://picsum.photos/1280/720?random=1" alt="image-1" />
    <div class="description">image 1</div>
  </section>
  <section>
    <img src="https://picsum.photos/1280/720?random=2" alt="image-2" />
    <div class="description">image 2</div>
  </section>
  <section>
    <img src="https://picsum.photos/1280/720?random=3" alt="image-3" />
    <div class="description">image 3</div>
  </section>
  <section>
    <img src="https://picsum.photos/1280/720?random=4" alt="image-4" />
    <div class="description">image 4</div>
  </section>
  <section>
    <img src="https://picsum.photos/1280/720?random=5" alt="image-5" />
    <div class="description">image 5</div>
  </section>
  <footer>
    <p class="leading-loose">Images from <a class="no-underline" href="https://unsplash.com">Unsplash</a></p>
  </footer>
</div>

可能な限りシンプルな構成にしてみたよ。
footer は画像利用のライセンス表記だからあまり気にしないで欲しい。

scss

まず @use でインポートしているのはいわゆる reset css だね。
各ブラウザ間の差異を打ち消す css なので必ずしも必要というわけではない。

src/scss/index.scss
@use '../../node_modules/destyle.css/destyle.css';

body {
  font-size: 16px;
  color: #fff;

  > div {
    position: relative;
  }
}

section {
  position: sticky;
  top: 0;
  display: block;
  width: 100vw;
  height: 100vh;
}

img {
  position: absolute;
  object-fit: cover;
  object-position: center center;
  width: 100%;
  height: 100%;
}

footer {
  position: sticky;
  bottom: 0;
  display: block;
  padding: 15px;
  background: rgb(255 255 255 / 30%);

  p {
    color: #000;

    a {
      color: #fff;
    }

    &.leading-loose {
      text-align: right;
    }
  }
}

.description {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  font-size: 5rem;
  text-align: center;
  text-shadow: 1px 1px 15px rgb(0 0 0);
  transform: translate(-50%, -50%);
}

要所を解説すると section に関する指定が今回の本懐。
position: sticky;にすることでスクロール時に要素が隠れるまで固定表示にしている。
ただしそのままだと中の要素のサイズによってサイズが変動してしまうので 1 セクションを 1 ページとするためにwidth100vw[2] height100vh[3] とする。
これにより section が画面サイズを気にせずにページサイズになる。

中のコンテンツは <img src="https://picsum.photos/1280/720?random=n" alt="image-n" /> で背景画像を表示している。
https://picsum.photos/1280/720 が毎回指定したサイズでランダムで画像を返してくれるので今回のサンプルで利用させてもらってるよ。
そしてこの画像自体もサイズは section と同じサイズまで調整して background-size: cover と指定したのと同様にしている。
あとは div で中に文字を表示しているだけでこの辺は css の基本がわかっていれば特に難しい話でもないので割愛するよ。

まとめ

どうだろうか。
こんな感じでサクッと開発環境を構築して適当に css 書いてパララックスを実装してみた。
今回は見た目でわかりやすいよう画像を背景に無理やり指定しているけど section に背景色を指定するだけで画像も使わずもっと簡単にパララックスを実装できる。
なにかの参考になると幸いだ。

脚注
  1. ソースマップとはコンパイルしたファイルのコンパイル前の行番号などをマッピングするために使われるデバッグ用のファイル ↩︎

  2. 画面に対する幅の割合 100vw なら画面幅に対して横幅 100% ↩︎ ↩︎

  3. [2:1] と同様に高さ。 ↩︎

Discussion