Gatsby で美少女フィギュアレビュー用の Gatsby Theme を作った話。
見た目はこんな感じ↓。
まぁ、美少女フィギュアレビュー用とは書いたけど、普通に写真全般に特化したThemeだと思ってもらって良い(いわゆる釣りタイトル)。
技術的な解説とかをしていくよ❗
モチベ
そもそも、ブログを引っ越ししたかったのがきっかけ。
今のブログは Hexo 製なんだけど、
細かいところのカスタマイズがしづらいんだよね。EJSにどうにも慣れなくて...。
探り探りでカスタマイズしたのも数年前で、もう全然覚えてないわけ。
で、秘伝のタレ化しちゃったから、いっそ一から作ろうと思って、別のSSGフレームワークをあさり始めた。
JekyllとかHugoとかもあったんだけど、Gatsbyに決めた。
人気もすごいし、Reactだし、表示が爆速だしで良さげだったため。
誤算だったのは、Gatsbyで美少女フィギュアレビューブログを書いてるやつはいなかったこと...なぜだ...。
皆さん頭良さそうな技術系ブログばっか作ってて、写真がメインのStarterとかThemeが意外とない❗
(自分の探し方がイマイチな可能性は大きいが。)
しょうがないから全部自分で作った。
作ってるうちに「自分だけで使うのももったいねえな...」と思い始めたので、Themeと Starter も作ったった。
皆さんも美少女フィギュアレビューブログ作ろう❗❗❗私も作ったんだからさ💢💢💢
機能
他、細かいところは Readme 読んでね。
1. 画像をできるだけ大きく表示
↓みたいに記事の横幅いっぱいまで画像拡大するようにしてる。
フィギュアレビューブログで画像が小さいのは致命的なんだよね。
可能な限り画面いっぱいにかわいこちゃんを表示したい❗
ただ、縦位置で撮った縦長写真で横幅いっぱいにすると、PCで見た時にでかすぎるので、そこは抑えてある。
縦幅が最大でスクリーンの高さまでになるようにした。
gatsby-remark-images
を使ってるなら、↓のようにすればよい。
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
wrapperStyle: (image) =>
`max-width:${(image.aspectRatio * 100).toFixed(2)}vh`, // See [issue: Can't specify max-width](https://github.com/gatsbyjs/gatsby/issues/15578) .
},
},
]
ちなみに、 max-height
を指定するとレイアウトが崩れちゃったんだよな...CSSは謎。
2. レスポンシブ
イマドキはレスポンシブじゃないとお話にならない。
弊ブログのGoogle Analyticsの結果が↓だけど、もう5割以上はスマホなんだよね。
レスポンシブ対応にあたっては、CSSのFlexとGridが大活躍だった。
部分的に使うのではなく、むしろ全体のレイアウトに使うのが良い。
- ヘッダ
- メイン
- サイドバー
- フッタ
とあったときに、メインとサイドバーをFlexItemにすれば、
画面幅を小さくしたときに自動でサイドバーが回り込んでくれる。
このあたりは書くこと多すぎなので、あとで別途解説する...かも。
3. Markdown(MDXじゃなく)
Pure MarkdownとMDXでどっちを採用するかは結構迷った。
MDXにすると、React Componentが使えて、記事ごとの表現力が上がる。
ただ、それって当然React Componentに依存するわけで、
将来的にGatsbyから引っ越すときに枷になりそう...と思ったので却下。
あと、URLを <
と >
で囲った書き方ができなくなるのもちょっと嫌。ただの上位互換じゃないんかい❗
さらに、あれこれ調べてたら、Pure Markdownでも表現力は補える方法があった。Special hooksでで解説。
4. Special hooks
『Special hooks』ってのは自分が勝手に作った言葉なので注意。
特定の条件のMarkdownの記述にフックして、任意のReact Componentを作る機能。
例えば、タイトルに left
と right
を持った2枚の画像が並んでいたら、
↓のような画像比較スライダーを作ったりできる。
設計的には、gatsby-transformer-remarkが作るHTML抽象構文木(hast)と hast-util-to-jsx-runtime
を利用する。
例えば、↑の画像比較スライダーの例だと↓のようになる。
- hastをパースして、タイトルが
left
とright
から始まる2枚の画像を探す。 - ↑の画像を子に持つ
p
タグをImageCompareSlider
タグにする。 -
hast-util-to-jsx-runtime
でhastをReact Elementに変換-
components
オプションで、ImageCompareSlider
タグを同名のReact Componentへ変換するようにしておく。
-
これも詳細は別途解説記事を作る...かも。
5. Tailwind CSSサポート
以前、Tailwind CSSは別のプロジェクトでいじってて使い勝手が良かったので、今回も使いたい。
...が、これが結構手間取った。
まず、Themeとか関係なく、GatsbyでTailwind CSSを使う方法は検索すると出てくる。
しかし、Themeでとなるとヒットしない...。
Gatsby Themeは結構特殊で、ThemeのComponentをShadowingしたときにもTailwind CSSが使えるようにする必要があるんだよね。
そうなると、ディレクトリ構成的には2箇所でTailwind CSSを使えるようにしなきゃならない。
最初はThemeとThemeを使う側の両方でTailwind CSSをセットアップしてた。
PostCSSの有効化も tailwind.config.js
の用意も gatsby-browser.js
の global.css
の import
も2箇所でやってた。
これでも正常に動いてたんだけど、ShadowingするComponentを増やしたら急にレイアウトが崩れだした❗
デバッグしたら、Tailwind CSSのClass定義が重複してて、media-queryなどの順番がめちゃくちゃになってた。
原因は gatsby-browser.js
の global.css
の import
を2箇所でやってたのが悪さをしてた。
これが重複すると、Theme側とThemeを使う側でClass名が別々に定義されて、重複しちゃうらしい。
(これに気づくまでにめっっっっちゃめちゃ時間かかった...。)
結局、Tailwind CSSのセットアップはThemeを使う側に一本化することにした。
そちらでPostCSSを有効化して、 tailwind.config.js
も global.css
も用意してもらう。
ただ、Theme側で tailwind.config.js
を記述したい部分もあったので、Theme側にも tailwind.config.js
を用意して、Themeを使う側で require
してもらうことにした。
Theme側の tailwind.config.js
が↓。
const path = require(`path`);
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
// See [Tailwind CSS | Working with third-party tools](https://tailwindcss.com/docs/content-configuration#working-with-third-party-libraries) .
path.join(
path.dirname(require.resolve(`@tenpamk2/gatsby-theme-figure-blog`)),
"**/*.{js,jsx,mjs,ts,tsx}"
),
],
theme: {
extend: {
dropShadow: {
title: [
`0 1px 1px rgb(100% 100% 100% / .8)`,
`0 2px 3px rgb(0% 0% 0% / .5)`,
`0 0px 20px rgb(0% 0% 0% / 1)`,
],
},
typography: {
DEFAULT: {
css: {
".gatsby-resp-image-wrapper": {
boxShadow: `0 0 1rem rgb(0% 0% 0% / .5)`,
borderRadius: `0.5rem`,
overflow: `hidden`,
},
// 中略
},
},
},
},
},
plugins: [require(`@tailwindcss/typography`)],
};
Themeを使う側の tailwind.config.js
が↓。
const defaultOptions = require(`@tenpamk2/gatsby-theme-figure-blog/tailwind.config.js`);
/** @type {import('tailwindcss').Config} */
module.exports = {
...defaultOptions,
...{
content: [...defaultOptions.content, `./src/**/*.{js,jsx,mjs,ts,tsx}`],
},
};
おまけ: 完走した感想
疲 れ た 。
2022年12月からGatsbyをいじりはじめて、今日までかかってしまった。
最終的に理解しなきゃいけない要素は↓。
- Gatsby
- Gatsby Theme
- GraphQL
- React
- JavaScript
- HTML
- CSS
- Tailwind CSS(typography含む)
- npm(ディレクトリ構造、workspace、publish...)
- Netlify
- Git(submoduleによるMarkdownと画像だけ別リポジトリ管理)
さすがに学習コストが高すぎた...。本職は組み込み屋さんやぞ私は...。
でも楽しかったのでOK。
で、ここまでやっておいて実はまだ引っ越しはできてないんだよねw
Hexo用に書いてた記事を新ブログ用に手直ししないといけなくて、それが面倒。
あと何日で弊ブログは新ブログに移行できるのやら...乞うご期待。