- 投稿日:2020-05-30T23:46:44+09:00
GatsbyにDarkModeをつける
はじめに
本記事は https://tech-blog.yoshikiohashi.dev/posts/start-gatsby-blog-darkmode のクロスポスト記事になります。
この記事はGatsbyというヘッドレスCMS技術で構成されています。今回は「エンジニア初心者でもできる」を前提に以下の構成で記事を作成していこうと思います。
- Gatsby始めるまで
- GatsbyにShare機能、OGPタグをつける
- タグ機能、カテゴリ機能をつける(基礎編)
- タグ機能、カテゴリ機能をつける(応用編)
- GatsbyにTableOfContents(目次)をつける
- DarkModeをつける(本記事)
内容
DarkModeかっこいいですよね。私は大抵のアプリのテーマをDarkModeにして使用しています。みなさんはどうでしょうか?目にも良くて簡単におしゃれになるDarkModeをブログに取り入れてみましょう!
こんな内容になっています。
- GatsbyのPluginで適用する
- 素のCSSを使った方法
- SCSSでも適用できる方法
GatsbyのPluginで適用する
これが一番手っ取り早いかもしれません。
gatsby-plugin-dark-modeをインストール
yarn add gatsby-plugin-dark-mode
// gatsby-config.js module.exports = { plugins: ['gatsby-plugin-dark-mode'], }使い方
ThemeToggler
をImportしたコンポーネントを作成します。import React from 'react' import { ThemeToggler } from 'gatsby-plugin-dark-mode' class MyComponent extends React.Component { render() { return ( <ThemeToggler> {({ theme, toggleTheme }) => ( <label> <input type="checkbox" onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')} checked={theme === 'dark'} />{' '} Dark mode </label> )} </ThemeToggler> ) } }このPluginはLocalStorageでDarkかそれ以外かを判断しているみたいです。
global.cssを修正する
global.cssがない場合は、bodyタグでメインカラーを制御しているファイルを見つけて以下のように修正しましょう。
/* global.css */ body { --bg: white; --textNormal: #222; --textTitle: #222; --textLink: blue; --hr: hsla(0, 0%, 0%, 0.2); background-color: var(--bg); } body.dark { -webkit-font-smoothing: antialiased; --bg: darkslategray; --textNormal: rgba(255, 255, 255, 0.88); --textTitle: white; --textLink: yellow; --hr: hsla(0, 0%, 100%, 0.2); }Layout.jsを修正する
CSSまで適用させたらあとはその変数を使用するだけです。Layout.jsを変更しましょう。
class Layout extends React.Component { render() { return ( <div style={{ backgroundColor: 'var(--bg)', color: 'var(--textNormal)', transition: 'color 0.2s ease-out, background 0.2s ease-out', }} > ... </div> ) } }素のCSSを使った方法
この方法は動的にCSSを変更できませんが、ユーザデバイスの設定に応じてテーマを変えることができます。
メリットとしては「素のCSSで構成されている, コストが低いのでとりあえず導入したい」になります。
cssの変更
まずは皆さんのプロジェクトのbodyタグもしくはroot:に設定されてるCSSを確認してください。
確認ができたら以下のCSSを加えていきましょう。
@media (prefers-color-scheme: light) { --theme-base: white; --theme-font: black; --theme-accent: red; } @media (prefers-color-scheme: dark) { --theme-base: black; --theme-font: white; --theme-accent: pink; } body { background-color: var(--them-base); color: var(--them-font); }prefers-color-scheme は CSS のメディア特性で、ユーザーがシステムに要求したカラーテーマが明色か暗色かを検出するために使用します。
とのことなので各デバイスの設定状況によってprefers-color-schemeの設定値が変わるということですね。ユーザデバイスに準拠するのでこのCSSだけでは手動で変更できませんが、最低限の対応としては良いと思います。
IEは。。。
やはりかというべきかIEは非対応とのことなのであしからず。。。というか無視しましょう!w
SCSSでも適用できる方法
先程のCSS変数を使用した応用になります。CSS変数をSCSS変数にラップしてあげればいいです。
// variables.scss :root{ @media (prefers-color-scheme: light) { --color-base: #222; --color-primary: #5D93FF; --color-secondary: #F7A046; --color_background-base: #FFF; } @media (prefers-color-scheme: dark) { --color-base: #FFF; --color-primary: #5D93FF; --color-secondary: #F7A046; --color_background-base: #282828; } @media (prefers-color-scheme: no-preference) { --color-base: #FFF; --color-primary: #5D93FF; --color-secondary: #F7A046; --color_background-base: #282828; } } $color-base: var(--color-base); $color-primary: var(--color-primary); $color-secondary: var(--color-secondary); $color_background-base: var(--color_background-base);やってみた
MacがDarkModeのとき
MacがLightModeのとき
まとめ
いかがでしたでしょうか。今回Gatsbyに限らず一般のCSSでも使用できる方法も合わせて紹介しました。状況に応じて必要なのを低コストで実現できると時間も取られないので良いですね!
一旦Gatsby特集は終わりますが、ちょいちょい自分でカスタマイズしていく予定なのでその度にご紹介できればと思います〜。それではまた。
参考
- 投稿日:2020-05-30T18:07:41+09:00
PHPと Vue.jsで簡易掲示板を作ろう〜その1(PHP編)〜
初めに
3つのパートに分けて
1.PHPでとりあえず動く掲示板を作る←今回はここ
2.SCSSで簡単なデザインを作る
3.Vue.jsで少しリッチな動きをつける目次
・誰向けですか?
・このパートでの完成イメージとデモサイト
・PHPの記述と解説
・HTMLの記述と解説
・*の解説
・まとめ誰向けですか?
・PHP初心者
・Vue.js初心者
・PHPで特に作りたいものがない人このパートでの完成イメージとデモサイト
デモサイト
簡易掲示板へようこそ(XSS対策済み)〜完成イメージ〜
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
このようにクロスサイトスクリプティング(XSS)の対策をしています。PHPの記述と解説
index.php<?php // htmlspecialchars()でHTMLで本来直接書くことのできない<>などの記号を書けるようにする // メッセージ欄にscriptを記述する輩への対策(XSSの防止)*1 function h($v) { return htmlspecialchars($v, ENT_QUOTES, 'UTF-8'); } $FILE = 'all_data.text'; // DBを使わずファイルに保存する $user_id = uniqid(rand().'_'); // IDを作る(ランダムな数値_13文字の文字列)が出力される*2 date_default_timezone_set('Asia/Tokyo'); // ↓date()でどの地域の時間を使用するか決める $date = date('Y年/m月/d日/H:i'); // date(Y,m,d,H,i)に↑で設定した時間が入る*3 $input_text = ''; // 入力するテキストを変数として代入 $post_data = []; // 一回の投稿のデータを入れる,($user_id, $date, $input_text)を入れる $all_data = []; // 全ての投稿のデータを入れる // file_exists(ファイル名)でこのファイルが存在するか調べる if(file_exists($FILE)) { //json_decode()でJSON形式のデータを配列に戻す //file_get_contents()で$FILEを読み込む $all_data = json_decode(file_get_contents($FILE)); } // $_SERVERにはHTTPサーバやHTTP通信に関わる情報が格納されている // $_SERVER['REQUEST_METHOD']でブラウザからのリクエストがGETかPOSTか判別する*4 // もしPOSTのリクエストがあったら if($_SERVER['REQUEST_METHOD'] === 'POST') { // リクエストを受け取った時textが空ではなかったら(送信ボタンが押された時) if(!empty($_POST['text'])) { // $post_textに投稿されたテキストを代入 $input_text = $_POST['text']; // 新しく投稿されたデータ(データを配列にして入れる)HTMLで表示する時に使う $post_data = [$user_id, $date, $input_text]; // 投稿をファイルに保存する $all_data[] = $post_data; // ファイルに保存する file_put_contents($FILE, json_encode($all_data)); } //header() //$_SERVER['SCRIPT_NAME']は現在のスクリプトのパス(簡単に言うと今いる場所のURL) header('Location:' . $_SERVER['SCRIPT_NAME']); //プログラム終了(exitなかったら後に書かれた処理も実行してしまうから) exit; } ?>HTMLの記述と解説
HTMLの記述は同じファイルでも分けても好みでOK(今回は続けて同じファイルに記述します)
index.php<div class="container"> <h1>簡易掲示板へようこそ(XSS対策済み)</h1> <!-- 投稿ボタン --> <form method="post"><!-- 中の投稿ボタンが押されたらPOSTのリクエストを送る --> <input type="text" name="text"> <input type="submit" value="投稿する"> </form> <table> <?php foreach((array)$all_data as $post_data) : ?> <tr> <form method="post"> <td> <!-- $post_data[2]は$post_text(テキストデータ) --> <?php echo h($post_data[2]); ?> </td> <td> <!-- $post_data[1]は$date(日付) --> <?php echo $post_data[1]; ?> </td> </form> </tr> <?php endforeach; ?> </table> </div>~*の解説~
<!-- *1ENT_QUOTES:["],['],[<],[>]が普通の文字として出力される *2uniqid()だけでは同じタイミングで実行すると同じ値が生成されるのでrand()を入れることで回避 ↑マイクロ秒で同じでないとかぶらないので念のためである *3公式マニュアルにdate()の日付文字列の書式が解説されている(分かりやすい)https://www.php.net/manual/ja/function.date.php *4 GET:何か情報を検索したり取得するために使うためのメソッド POST:登録処理や更新処理などの、書き込みがありリソースが更新される可能性のある処理に対して使うメソッド もっと詳しく分かりやすい解説記事:https://qiita.com/kanataxa/items/522efb74421255f0e0a1 -->
まとめ
今回のパートではとりあえず動く掲示板を作成しました!
PHP学習してまだ日が浅いので間違いがあるかもしれません。その時はお教えください?♂️
メソッドやプロパティを一つ一つ調べながら学習するといいことが今回分かりました!
この記事を見てくださったあなたの成長を応援します!!
ーーーー
次のパート:PHPと Vue.jsで簡易掲示板を作ろう〜その2( SCSS編)〜この記事もいかがですか?
初心者に捧げるハンバーガーメニューの作り方
初心者に捧げるヘッダーの作り方
初心者に捧げる〜PHPを使って九九の表を作ろう〜
- 投稿日:2020-05-30T15:59:47+09:00
css before after
See the Pen QWjedXr by 中村一貴 (@kazukkinakamura) on CodePen.
前後に文字を置けたりする
他の使用例
- 投稿日:2020-05-30T15:35:58+09:00
multiline ellipsis
See the Pen vYNogVG by 中村一貴 (@kazukkinakamura) on CodePen.
IE 11はok
参考
https://tenman.info/labo/css/?p=5773
経緯
- 投稿日:2020-05-30T11:25:25+09:00
BEM vs OOCSS vs SMACSS 【CSS命名規則比較】
CSSとは
Cascading Style Sheetsの略で、
ウェブページのスタイルを指定するためのマークアップ言語のこと。
HTMLなどで書かれた文書を色やフォントやレイアウトなどを変えることが可能。
CSSリファレンス | MDN命名規則とは
プログラミングで、変数、型、関数などに名前を付ける際のルールや慣習のこと。
命名規則を設けることで、見やすいコードにしたり、チームで開発している場合には、
コードの統一感を出すことができ、総じて改修のしやすいコードを書くことができます。CSS命名規則
BEM設計 ( ベム )
「Block Element Modifier」の略で、
クラス名をレイアウト・コンテナ要素(Block)・パーツ要素(Element)・状態(Modifier)の組み合わせ
によって記述するCSS設計方式。HTML(書き方)<div class="レイアウト・コンテナ要素"> <div class="レイアウト・コンテナ要素__パーツ要素--状態"></div> </div>HTML(例)<div class="card"> <h3 class="card__title">タイトル</h3> <a href="" class="card__link card__link--blue">リンク</a> </div>OOCSS設計 ( オーオーシーエスエス・オブジェクト指向CSS )
「Object Oriented CSS」の略で、
クラス名を構造・状態(見た目)の大きく2種類に分けた組み合わせによって記述するCSS設計方式。HTML(書き方)<div class="構造(レイアウト要素)"> <div class="構造(パーツ要素) 状態(見た目)"></div> </div>HTML(例)<div class="main"> <div class="card"> <h3 class="title">タイトル</h3> <a href="" class="link bg-blue">リンク</a> </div> </div>SMACSS設計 ( スマックス )
「Scalable and Modular Architecture for CSS」の略で、
クラス名をベース要素(リセット)・レイアウト要素・パーツ要素・状態・見た目の5つの組み合わせ
によって記述するCSS設計方式。HTML(書き方)<div class="レイアウト要素"> <div class="パーツ要素 状態 見た目"></div> </div>HTML(例)<div class="l-main"> <div class="card"> <h3 class="title">タイトル</h3> <a href="" class="link theme-blue">リンク</a> </div> </div>例 ( コード比較 )
BEM設計
See the Pen CSS_BEM-ex by engineerhikaru (@engineerhikaru) on CodePen.
OOCSS設計
See the Pen CSS_OOCSS-ex by engineerhikaru (@engineerhikaru) on CodePen.
SMACSS設計
See the Pen CSS_SMACSS-ex by engineerhikaru (@engineerhikaru) on CodePen.
まとめ ( メリット・デメリット )
これら3つは、いずれもメリット・デメリットがあり、チームメンバーとの話し合いで決めましょう。
下記に大きく分けたメリット・デメリットを表に記しておきます。
メリット デメリット BEM CSSの構造がシンプルになる・Sassとの相性が良い クラス名が長くなる・総コード量が多くなる OOCSS クラス名が短い・ネーミングが楽 CSSが複雑になる・例外に弱い SMACSS ユーザ体験が一貫する・メンテナンス性が高い 規則を知らないと意味不明・例外に弱い 個人的には、OOCSSをよく使うかな...
SMACSSについては、書き方がかなり独特なので、また機会があれば紹介します(^^)
- 投稿日:2020-05-30T05:15:38+09:00
初心者によるプログラミング学習ログ 330日目
100日チャレンジの330日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
330日目は、
おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) May 29, 2020
330日目 2h
・ポートフォリオ作成2h:制作物一覧部分作成#早起きチャレンジ#駆け出しエンジニアと繋がりたい#100DaysOfCode
- 投稿日:2020-05-30T02:51:04+09:00
<style scoped>で子コンポーネントのスタイルがどう変わるか検証した(Vue CLI)
結論
<style scoped>
で子コンポーネントスタイルを設定したら、そのスタイルは子コンポーネントの一番上のルートにだけ適応されるというルールを検証した結果、その通りだった。
参考:
vue-loader -子コンポーネントのルート要素-
vue-loaderのScoped CSSのスタイルが子コンポーネントのルート要素に効いてしまって辛いVue CLIを触り初めて1週間、コンポーネントの
<style>
の書き方が間違っていて、思い通りのレイアウトにならず苦労した。
後日また同じことで悩まないように、やった手順とよくなかった点をメモしておく。
そしてこの記事が誰かのためになれると嬉しい。検証画面の構成
コンポーネントの構成
作成したファイル
- src - components - ContinueButton.vue - views - Pj002.vueソース
↓コンテニューボタンの単一コンポーネント
ContinueButton.vue<template> <div class="continue-container"> <p> CONTINUE <span class="continue-text"> > </span> </p> </div> </template>↓メインページ *コンテニューボタンのスタイルはすべてココに書いている
Pj002.vue<template> <div class="background"> <main> <ContinueButton></ContinueButton> </main> </div> </template> <script> import ContinueButton from '@/components/ContinueButton.vue'; export default { name: 'Pj002', components: { ContinueButton, }, }; </script> <style> @import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap'); /* Pj002.vue全体の背景 */ .background { height: 90%; position: absolute; top: 10%; right: 0; bottom: 0; left: 0; background-color: lightblue; } /* コンテニューボタンの白いボーダーラインなどを設定 */ .continue-container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 500px; height: 150px; border: 5px solid #ffffff; text-align: center; line-height: 45px; opacity: 1; } /* コンテニューボタンの文字フォントなどを設定 */ .continue-container p { position: absolute; width: 100%; top: 20%; left: 60%; transform: translate(-50%, -50%); letter-spacing: 1.6px; color: #ffffff; font: 48px/32px Bebas Neue; opacity: 1; } /* コンテニューボタンの"CONTINUE"と">"の間の余白を設定 */ .continue-text { text-align: left; margin-left: 80px; } </style>
<style>
を変えたらどうなるか
<style>
のままの場合見た目
理想通り。
スタイルがscopedになっていないので、CSSはグローバルで定義されていることになり、コンテニューボタンのレイアウトも問題なく表示される。
<style scoped>
にした場合見た目
変わったところ、変わらなかったところ
- 白いボーダーラインは何も変わらずきちんと表示されている
- 文字のフォントが変わっている
- "CONTINUE" と ">" の間の余白がなくなっている
<template>
のclass属性も上記の順番で設定している。
冒頭の結論で出した通り、やはり子コンポーネントの1番上の要素は
<style scoped>
にしたにも関わらずレイアウトが適応されている。
それ以下のスタイルは適応されていない。
ちなみに<style module>
にした場合見た目
変わったところ、変わらなかったところ
子コンポーネントのスタイルは一番上の要素であっても適応されない。 ・・・!!?
(※"CONTINUE >"という文字列も表示されなくなった点については理由がわかっていないので、どなたかわかる方がいれば教えていただきたいです。)ソース
class属性の記載方法が
v-bind
に変わるのでソースを載せておく。ContinueButton.vue<template> <div :class="$style.continue_container"> <p> CONTINUE <span :class="$style.continue_text"> > </span> </p> </div> </template>Pj002.vue<template> <div :class="$style.background"> <main> <ContinueButton></ContinueButton> </main> </div> </template> <script> import ContinueButton from '@/components/ContinueButton.vue'; export default { name: 'Pj002', components: { ContinueButton, }, }; </script> <style module> /* Pj002.vue全体の背景 */ @import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap'); .background { height: 90%; position: absolute; top: 10%; right: 0; bottom: 0; left: 0; background-color: lightblue; } /* コンテニューボタンの白いボーダーラインなどを設定 */ .continue_container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 500px; height: 150px; border: 5px solid #ffffff; text-align: center; line-height: 45px; opacity: 1; } /* コンテニューボタンの文字フォントなどを設定 */ .continue_container p { position: absolute; width: 100%; top: 20%; left: 60%; transform: translate(-50%, -50%); letter-spacing: 1.6px; color: #ffffff; font: 48px/32px Bebas Neue; opacity: 1; } /* コンテニューボタンの"CONTINUE"と">"の間の余白を設定 */ .continue_text { text-align: left; margin-left: 80px; } </style>開発者ツールでの確認結果
まとめ
<style scoped>
にしても、子コンポーネントの一番上のルートにはスタイルが適応されてしまうので注意すべき。
一部だけ反映されるから「CSSどっかいじってしまったかな?」なんて微調整し始めると沼。
公式のスタイルガイドにて、<style scoped>
の使用は必須レベルで推奨されているので、きちんと使いこなせるようになりたい。参考:
スタイルガイド -コンポーネントスタイルのスコープ-
【Vue.js】Scoped CSSよりCSS Modulesの方がベターだった件