Reactジャンプ率ジェネレーターの続きです。前回は独自フックで関数を抽出し、全てのツマミが動いくようになりました。今回はこのツマミの値をstyled-componentsに埋め込んで、動的にCSSスタイルを変更させたく。それではいきましょう!
【目次】
- 前回のおさらい
- styled-componentsを動的に変える事例(propsを使う方法)
- Settingコンポーネントのタグを変更
- フックの初期値を変更
- Settingコンポーネントのスタイルを設定
- Exampleコンポーネントを作成
- Exampleコンポーネントの静的なスタイルを設定
- P、Section、H2コンポーネントに動的なスタイルを設定
- ジャンプ率ジェネレーター完成(ブラウザ挙動)
- 最後に
※参考:前回記事
【React】独自フックで関数を抽出、全てのツマミが動いた!(ジャンプ率ジェネレーター) - クモのようにコツコツと
※参考:ReactでWebアプリを作るシリーズまとめ
qiita.com
前回のおさらい
独自フックで関数を抽出し、全てのツマミが動いくようになった!
※参考:【React】独自フックで関数を抽出、全てのツマミが動いた!(ジャンプ率ジェネレーター) - クモのようにコツコツと
今回はこのツマミの値を元にCSSを動的に変更させたい。
styled-componentsを動的に変える事例(propsを使う方法)
styled-componentsを動的に変えている事例を調べると下記のような内容があった。
※参考:[React & TS] styled-componentsで動的にスタイルを変更する - Qiita
Adapting based on props
You can pass a function ("interpolations") to a styled component's template literal to adapt it based on its props.
小道具に基づいて適応 関数(「補間」)をスタイル付きコンポーネントのテンプレートリテラルに渡して、その小道具に基づいて適合させることができます。
小道具ってprops
のことね。props
からinputの値を渡して、その値を条件に三項演算子で分岐処理する。
propsでの動的な変更は以前やっている。
※参考:【React】コンポーネントの属性値を読み込む(style、テキスト、四則演算) - クモのようにコツコツと
しかし、propsを使った事例はinputタグへの入力値によって、あらかじめ設定したスタイルを切り替える内容のようだ(例えば値が1000以上だったら文字を黒色から赤色にする、など)
今回、自分がやりたいのはinputタグの値そのものをCSSの値に入れること。前回、フックを使ってpタグに値を入れたように。
<section> <h2>行長</h2> <p>値:{lineLength}</p> <InputRange type="range" name="range" min="10" max="50" defaultValue={lineLength} onChange={ChangeLineLength}></InputRange> </section>
※参考:【React】独自フックで関数を抽出、全てのツマミが動いた!(ジャンプ率ジェネレーター) - クモのようにコツコツと
そのためpropsは使わなかった。
これまで、styled-componentsは関数コンポーネントの外に設定しておりフックは関数コンポーネントの中に設定していた。
styled-componentsを関数コンポーネントの中に設定してもいいんだ、という意味では上記の事例は参考になった!
Settingコンポーネントのタグを変更
Settingコンポーネント
<Setting> <dl> <dt> 行長:{lineLength}文字 <span className="css">( max-width: {lineLength}em; )</span> </dt> <dd> <input type="range" name="range" min="10" max="50" defaultValue={lineLength} onChange={ChangeLineLength} /> </dd> <dt> 行間:{lineHeight}倍 <span className="css">( line-height: {lineHeight}em; )</span> </dt> <dd> <input type="range" name="range" min="1" max="3" step="0.05" defaultValue={lineHeight} onChange={ChangeLineHeight} /> </dd> <dt> ジャンプ率:{Math.round(jumpRate * 100)}% <span className="css">( font-size: {jumpRate}em; )</span> </dt> <dd> <input type="range" name="range" min="1" max="4" step="0.05" defaultValue={jumpRate} onChange={ChangeJumpRate} /> </dd> </dl> </Setting>
- 前回section、h2、pタグの構成だったが、dl、dt、ddタグの構成に変更(コンパクトな見た目にするため)
- 前回は「行長:n」など数値のみ表示していたが「行長:n文字」など単位も追加(dtタグ)
- さらにdtタグの中のspanタグ
.css
部分にcssの設定値も追加 - 行間は最大値
max
を2.5から3に変更、しきい値step
を0.01から0.05に変更 - ジャンプ率の最大値、最小値を3桁から1桁に変更、しきい値
step
を0.01から0.05に変更
ジャンプ率は「%」表示は3桁だがCSSはem
で1桁。そのためinputの設定値は1桁にして* 100
で3桁にした。
たまに割り切れない時があったため、Math.round()
で小数点を切り上げをした。
※参考:JavaScriptで四捨五入、切り捨て、切り上げする方法
フックの初期値を変更
ジャンプ率のフックの初期値を変更
const [lineLength, setLineLength] = useState(35); const [lineHeight, setLineHeight] = useState(1.75); const [jumpRate, setJumpRate] = useState(2); // 200から2に変更
- 変数
jumpRate
、setJumpRate
のuseState()
の引数を200から2に変更
先ほどのinputタグの設定値を1桁に変更したため。
Settingコンポーネントのスタイルを設定
スタイル設定もdl
、dt
、dd
タグの形で設定する
const Setting = styled.div` margin: 30px 0; dt { font-weight: bold; .css { font-weight: normal; } } dd { margin: 0 0 1em; } input { width: 100%; max-width: 600px; } `;
Setting
コンポーネントはdivタグにする- dtタグは太字だが中の
.css
はノーマルな太さ - inputタグの幅はSPに対応するため基本100%、最大600pxにする
こんな感じのコンパクトな見た目になった!
Exampleコンポーネントを作成
inputタグのツマミを変えた時に動的に見た目を返るサンプル部分のコンポーネントを作る。
<Example> <Section> <H2>タイトルです、ああタイトルです、タイトルです</H2> <P>本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。本文です。本文です。本文ですったら、本文です。</P> </Section> </Example>
Example
コンポーネントの中にSection
、H2
、P
コンポーネントが入っている
試行錯誤の結果こうなった。一番外側のExample
コンポーネントに静的なスタイルを設定し、内側のSection
、H2
、P
コンポーネントには動的なスタイルを設定する。動的なスタイルは関数コンポーネントの中に書く。
Exampleコンポーネントの静的なスタイルを設定
Example
コンポーネントに静的なスタイルを設定する
const Example = styled.div` background: #eee; display: inline-block; border-radius: 10px; font-size: 14px; section { margin: 30px; line-height: 1.75em; h2 { color: #000; line-height: 1.25em; margin: 0 0 1em; } p { margin: 0; } } `;
これらの設定はいつものように関数コンポーネントの外に書いている。
P、Section、H2コンポーネントに動的なスタイルを設定
次はinputタグのツマミと同期して動的に変えたいスタイルを設定。
const P = styled.p` line-height: ${lineHeight}em; `; const Section = styled.section` max-width: ${lineLength}em; `; const H2 = styled.h2` && { font-size: ${jumpRate}em; } `;
P
コンポーネント はpタグでline-height
の値にlineHeight
を埋め込んでいるSection
コンポーネント はsectionタグでmax-width
の値にlineLength
を埋め込んでいるH2
コンポーネント はh2タグでfont-size
の値にjumpRate
を埋め込んでいる
これらの設定はフックを埋め込みたいので関数コンポーネントの中に書いている。props
などは使わず、Setting
コンポーネントと同じ書き方で済んだ。
なお、当初H2
のスタイルは外側のコンポーネントに設定しているスタイルの詳細度に負けてしまって設定が変わらなかった。こちらの&&
を使う方法によってクラス名が二重になり、詳細度を上げることができた。
※参考:styled-componentsが反映されないときは詳細度を調べてみよう - りんごとバナナとエンジニア
Finally, the ampersand can be used to increase the specificity of rules on the component; this can be useful if you are dealing with a mixed styled-components and vanilla CSS environment where there might be conflicting styles:
最後に、アンパサンドを使用して、コンポーネントのルールの特異性を高めることができます。 これは、スタイルが競合する可能性のある、スタイル付きコンポーネントとバニラCSS環境が混在している場合に役立ちます。
また、以前やったような副作用フックuseEffect()
も不要だった。
※参考:【React】フック(React Hooks)事始め:useState、useEffect、useContext - クモのようにコツコツと
useEffect()
で囲ったところ、P
、Section
、H2
コンポーネントがスコープになってしまいJSXと連動されないエラー。
そしてuseEffect()
がない状態でも問題なく動くようだった。
Exampleコンポーネントのスタイル設定が完成
この見た目の行長・行間・ジャンプ率がinputタグのツマミを変えることで動的に変わる想定。
ジャンプ率ジェネレーター完成(ブラウザ挙動)
ジャンプ率ジェネレーター完成!
※参考:React App
下記の「行長・行間・ジャンプ率」記事を体験できるジェネレーター。どのくらいの設定値が適切か調べることができる。
※参考:【行長・行間・ジャンプ率】タイポグラフィ事始め(適度な箱組みとは) - クモのようにコツコツと
初期設定はこちら(推奨値)
行長:35文字、行間:1.75倍、ジャンプ率:200%
行長:35文字→47文字(本文の行長が広がる)
行長:35文字→24文字(本文の行長が狭まる)
行間:1.75倍→2.55倍(本文の行間が広がる)
行間:1.75倍→1.4倍(本文の行間が狭まる)
ジャンプ率:200%→320%(見出しのジャンプ率が上がる)
ジャンプ率:200%→135%(見出しのジャンプ率が下がる)
すべて変更してみる。
行長:43文字、行間:1.85倍、ジャンプ率:310%
ソース(GitHub)
※参考:GitHub - ryo-i/jump-rate-generator at 0e5d7a565913d6ef50ea97bcd81127485084cbd5
プレビュー(GitHub Pages)
※参考:React App
最後に
ということで、ジャンプ率ジェネレーターが完成しましたーー!
styled-componentsの値を動的に変更する方法はpropsを使う情報が多かったのですが、今回は使わずに済みました。
なんとなくstyled-componentsは関数コンポーネントの外側に書くイメージがあったのですが、関数コンポーネントの中に書いて動的な設定をしている事例も見受けられたので安心しました。
これがベストプラクティスなのか確証が持てていないのですが、やりたいことは実現できたのでいったん一区切りとしたく思います(よりベターな方法があったら続報を書きます)。
それではまた!
※参考:ReactでWebアプリを作るシリーズまとめ
qiita.com