gulp導入の覚え書き(前編)- Node.jsのインストールまで

gulpを使おうとなった時に以前行った手順は記憶の彼方なので、これまでのメモをまとめました。
(特にNode.jsまでは一度入れてしまえば中々入れ直すこともないと思うので忘れてしまいます)

☆長くなるので前・後編に分けました。後編はこちら

大まかな流れ

以下に沿って進めます。

1. homebrewをインストール  
 ↓  
2. anyenvをインストール  
 ↓  
3. nodenvをインストール  
 ↓  
4. Node.js(npm)をインストール  ・・・前編ここまで
 ↓  
5. gulpをインストール

1. homebrewをインストールする

homebrewとは

App Storeで扱っていない、開発をするためのソフトウェアをインストールする際に依存関係を管理してくれるツールです。

一言でいうと、macOSのパッケージ管理ツールです。
以前調べました(記事)。

homebrew=自家醸造=ユーザー自らがビルドする」でしたね!

日本語のhomebrew公式ページ
「これをmacOSのターミナルまたはLinuxのシェルプロンプトに貼り付けて下さい。」という部分を、コピペでコマンドラインで実行します。

これでbrewコマンドが使えるようになります。

【参考】homebrewについて

【簡単】MacにHomebrewをインストールする方法と基本的な使い方|新卒エンジニアの開発日記

2. anyenvをインストールする

anyenvとは

pyenvやrbenv、phpenv、nodenvなど「〜env」と名のついた、プログラミング言語バージョン管理ツールを一元管理するツールです。
各環境(仮想環境とか、プロジェクト)ごとに各言語のどのバージョンを使っているかを管理してくれます(と解釈しました)。

anyenvのメリットです。

  • 現在のバージョンを何に設定しているか、どのバージョンが入ってるかまとめて確認できる
  • 〜env系を簡単にインストールできる
  • 新しいプログラミング言語を追加しても.bash_profileや.zprofileなど(bashzshといったシェルの設定ファイル。パスを通す時に記述する)に書き込まずに(汚さなくて)済む
  • VM (VirtualMaschine)での開発でプロジェクトを切り替えるとき、いちいち VM を立ち上げ直す手間がない
  • プロジェクトごとにバージョンを切り替えて開発できる

VMのことなど、一部まだよくわかっていないですが、便利ということは分かりました。

anyenvのインストール方法は2つあります。 ※以下シェルがzshの書き方です。

方法1:brewコマンドを使う

brew install anyenv
echo 'eval "$(anyenv init -)"' >> ~/.zshrc
exec $SHELL -l

2行目は anyenv init - を実行する処理を echo>> を使って .zshrc に記述します。

3行目でシェルを再起動させます。

シェルを再起動させる簡単な方法 - Qiita

exec $SHELL -l とは以下の意味だそうです。

環境変数 $SHELL をログインシェルから起動させることを exec するという意味となり、ターミナルが再起動できるようになります。

まだ理解するには早かったみたいです...。

方法2:gitコマンドを使う

GitHubにあるリポジトリをクローンしてインストールします。

git clone https://github.com/riywo/anyenv ~/.anyenv
echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(anyenv init -)"' >> ~/.zshrc
exec $SHELL -l

GitHubに説明がありました(英語です)。

GitHub - anyenv/anyenv: All in one for **env

【参考】anyenvについて

anyenv + macOS環境構築 - Qiita

3. nodenvをインストール する

anyenvをインストールして使えるようになったanyenvコマンドから「〜env」をインストールできるようになります。

nodenvとは

プロジェクトごとにNode.jsのバージョンを自動で切り替えてくれるツールです。

コマンドラインでnodenvをインストールします。

anyenv install nodenv

exec $SHELL -l

以降のNode.jsのインストール手順もこちらに書かれています!

Node.jsのバージョンを自動で切り替えられるnodenvが超便利 - Qiita

コマンドの使い方が丁寧に書かれています!

anyenvとnodenvでNode.jsのバージョン管理をしよう! - to-R Media

4. Node.js(npm)をインストール する

npmはNode.jsをインストールすると、もれなくインストールされます。

まずグローバルでNode.jsのインストール、バージョンの設定をします。

グローバルでNode.jsをインストールする

Node.jsはバージョンを指定してインストールします。必要なバージョンをグローバルでインストールして、全体、各プロジェクトでバージョン指定を行って使います。

インストールできるバージョンの確認

ndenv install --list

バージョンがずらっと出てくるので、安定した最新のバージョンを選びます。
新規プロジェクトの場合は最新のものでOKです。
数字だけのもののうち、一番数が大きいものが最新です。

☆ここではv13.5.0をインストールしてみます。

インストール

nodenv install 13.5.0

グローバルでNode.jsのバージョン指定をする

インストールしただけでは使えないのでバージョンの指定をします。グローバルのバージョンがデフォルトになります。

グローバルでのNode.jsのバージョン指定

nodenv global 13.5.0

プロジェクト(ローカル)ごとにNode.jsのバージョン指定をする

バージョン指定をするファイルは .node-versionです。.node-versionファイルは直接作成する方法と、コマンドで作成する方法があります。

.node-versionファイルの中身

13.5.0

ローカルのNode.jsのバージョン指定

nodenv local 13.5.0

上記のコマンドで.node-versionファイルが作られます。
プロジェクト内に .node-versionファイルがない状態、すなわちバージョンを指定しない場合はグローバルで指定されているバージョンが使われます。

インストールしただけでは使えない、バージョン指定が必要ということなので、グローバルかプロジェクト、どちらかでバージョン指定が必要であることがわかりました。

バージョンの確認

node -v

または

node --version

ちなみにanyenvでは「〜env」ごとにインストールされている言語のバージョン(ここではNode.js)のリストと、指定されているバージョンが分かります。

anyenv versions

続きは後編で

後編ではgulpのインストールとnpmの使い方についてまとめます!

レスポンシブな画像の表示を考える

投稿するコンテンツの場合、アップする画像サイズを統一させられないのが常です。
いろいろな縦横比の画像を画面いっぱいに表示させる方法を模索しています。

wordpressなどでは、リサイズさせた画像を表示させたりするので、あまり頻繁ではありませんが、たまに詰まるときがあります。

ポイントは

  • レスポンシブ(拡大縮小しても縦横比は同じ)
  • 表示枠の中央に表示
  • 表示枠いっぱいに画像を表示する(余白が出ない)

これら3つをおさえることです。

現時点でこれがベスト!という書き方をメモします。

検証の条件

サンプル画像はこちらです。

f:id:yokoyoko_115:20210306003406j:plainf:id:yokoyoko_115:20210306003439j:plain

中央がわかりやすいと思ったものにしました。
(縦は微妙かもしれない)

これらはそれぞれ
427x640px
640x427px

のサイズで約長辺3:短辺2の比です。

※横長画像はコンテンツ幅に合わせて小さくなっています。
2つの画像の比があっていないように一見見えますが同じです!(錯覚?)

これらを、幅4:縦3の枠にいっぱいに表示させることを目指します。

上記の3つのポイントを見ていきます。

htmlはこのように書いて検証しています。

html

<p class="frame">
<img class="frame_img" src="https://drive.google.com/uc?export=view&id=18asPUoAeh3QanjaSkyp_q-ETAAvc74fr" alt="縦長写真の猫">
</p>
<p class="frame">
<img class="frame_img" src="https://drive.google.com/uc?export=view&id=1_DRrKwnmc1SzcdYMp992SoCr2-EkhKCb" alt="横長写真の猫">
</p>

レスポンシブな枠の高さの作り方

レスポンシブの際にいつも悩む高さの指定ですが、height または、padding-top で考えます。

heightの場合

height で%を使うと、親要素の高さから値を取るのであまり使うことはないと思います。

一方でvwという、ビューポートの横幅を基準とした単位では、階層が深い要素だと指定が難しいです(要素のvwの数値を出す計算が大変)。

padding-topの場合

padding では%は、要素の幅から計算します。
縦:横 = 1:2 の場合は、padding-topは幅100%の半分の50%になります。

padding-topの出し方
縦 / 横 x 100%

ですね。

なのでとても使えます!

疑似要素を使うといい点

padding-top を使うときは疑似要素を使いましょう、と調べると出てきます。
ですが、例えば幅4:縦3の枠で、表示枠が width: 80% という指定だった場合

.frame {
  width: 80%;
  padding-top: 60%;    /* ←3 / 4 x 80% */
}

と、わざわざ疑似要素を作らなくても枠が作れるのです。

padding-top で高さを作る場合は、どちらにしろ表示枠の中の子要素には position: absolute を指定することになるので、必ずしも疑似要素が必要、というわけではありません。

ではなぜ疑似要素を作ることを勧められているのかというと

  • padding-top の計算がしやすい(縦 / 横 x 100% と、100%で計算できる)

ぐらいしか思い浮かびませんでした。
もっと複雑に要素を含ませたい場合に擬似要素の方が都合が良いのかもしれません。

☆ちなみに疑似要素(::before, ::after)はインライン要素なので、この場合 display: block を入れます。

画像を中央に配置する方法

中央というとまたまた position: absolute を使うか、または flexboxを使うかが考えられます。

position: absoluteの場合

.position_frame {
  position: relative;
  background-color: #000;
  padding-top: 15%;
  width: 20%;
  overflow: hidden;
}

.position_img {
  position: absolute;
  top: 0;
  bottom: 0;
  left:0;
  right: 0;
  margin: auto;
  width: auto;
  height: 100%;
}

position: absolute を使った中央配置の書き方はtop: 50%; left:50; transform: translate(-50%, -50%); transform: translateY(-50%); もありますが、私は↑の書き方のほうが好きです。 (transformを使わなくてはいけないケースがあったような)

flexboxの場合

.flex_frame {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000;
  width: 40vw;
  height: 30vw;   /* ←3 / 4 x 40vw */
  overflow: hidden;
}

.flex_img {
  width: auto;
  height: 100%;
}

paddingの部分にflexitemを置くことはできないので、flexboxでは height を使うことになります。
しかし使いづらい height を指定してまでflexboxにする意味はあまりなさそうです。

表示枠いっぱいはobject-fit: cover

imgタグを width: auto; height: 100%; とすると、画像の比率は保たれるものの、縦長画像の場合は高さが足りないことがあります。 width: 100%; height: auto; も同様です。

imgタグを使わずに枠の背景画像として background-size: cover を指定する方法もありますが、それができれば苦労しない、ということでここでは置いといて。
それ以外にある方法は、object-fit プロパティををつかう方法しかないと思います。

object-fit:cover で枠いっぱいに広げてくれます。
中央に配置する記述も不要!枠の大きさを決めるだけで良いなんて素敵です。
画像もwidth: 100%; height: 100%; でも歪む心配はありません。

こちらに詳しく書かれています!

1行追加でOK!CSSだけで画像をトリミングできる「object-fit」プロパティー | Webクリエイターボックス

object-fit プロパティは2021年3月現在ではIE以外で有効です。

Can I use... Support tables for HTML5, CSS3, etc

もう使ってもいいと思いますが、IE対応までしたいという場合は、潔くプラグイン入れたいところです。

IE11での画像のobject-fitの使用について – 東京のホームページ制作 / WEB制作会社 BRISK@22年新卒採用中

さらに前回の記事で書いたwidthとheight属性をimg要素に書けば完璧!

まとめ - 枠いっぱいのレスポンシブな画像表示の書き方

CodePenでの検証はこちらです。

See the Pen 画像のレスポンシブ表示検証 by yokoyoko (@yokoyoko_code) on CodePen.

うまくいかないときは

実際に私はうまくいきませんでした!
コードを同じようにコピーしてみても枠の高さがおかしい。
よくよく見ると親要素にdisplay: flexがかかっていました!

フレックスアイテム(flexboxの子要素)の高さはデフォルトで親要素いっぱいに広がります。なのでいくら子要素に高さを指定しても効かないようです。

そこで画像の枠である子要素に align-self: flex-start を設定することにより、高さが子要素の高さになります。

ちなみに

CodePenで画像を使っているものを見かけるのですが、方法がわかりませんでした。
調べて無料会員が画像を使う方法を会得しました!
個人でサーバーを持っていなかったらこの手があります。

CodePenの無料会員で画像を使うには | こんぷれ

最後に

自分の中ではベストな書き方がまとまった!とすがすがしさを感じていますが、人様が作ったサイトを見ることも大事ですね。
もっといい書き方があると思います。
研究しなくてはですね。

おしまい!

読み込む画像のCLSと遅延読み込みについて

Googleの、Search Consoleの「ウェブに関する主な指標」で不良のURLがありました。
引っかかっていたのは「CLS に関する問題: 0.25 超(モバイル)」です。

他の指標としてはLCP(Largest Contentful Paint: コンテンツの初回ペイント)やFID(First Input Delay: 初回入力遅延)がありますが、今回問題のCLSを中心に画像読み込みについて調べました。

Cumulative Layout Shift (CLS)

累積レイアウト変更。
ページを読み込んだときに、後から画像や動画が読み込まれて、その下の画像やテキストががくんと下がるものです。 Search Consoleでは値が大きいほど良くないとされ、0.25を超えると「不良」と言われます。

テキストよりも画像や動画の方が容量が大きいため、読み込みが遅れて一瞬レイアウトが崩れてしまいます。

解決法

画像が読み込まれる前に、あらかじめ画像の表示領域を確保しておくというものです。

方法1:imgタグに widthheight 属性を設定する

先にhtmlの widthheight の値を読んで領域確保→画像を読み込む、という動きなのでしょう。
しかしレスポンシブなページに固定値は書けない...その場合は元画像のサイズを入れておく、という記事も見かけました。

☆ちなみにwidthheight 属性の値はピクセル(「px」不要)または%で指定します。

方法2:cssでレスポンシブな箱を用意する

img 要素をさらに divp 要素で囲います。
レスポンシブな背景画像を配置するように、親要素(divp)に 画像の縦横比に合う padding-topを、さらに position: relative。子要素(img)には position: absolute をかけます。
個人的には position: absolute を乱用するのは気が進まないのですが、用法用量を正しく守れば問題ないでしょうか。

他にいいcssの書き方がないか探していきたいです。

widthとheightを指定すると画像の表示は早くなる?

という記事を見かけたのですが、それが上記のようなcssでもいいのか、htmlで書かなくては意味がないのか、そもそも表示速度に関係がないのか、はっきり分かりませんでした。

ここで累積レイアウト変更の問題は一旦解決なのですが、画像の最適化を考える上では大事な「画像の遅延読み込み」について調べました。

画像の遅延読み込み

ページ読み込み時に一気に画像を読み込まず、スクロールで表示領域に入ったときに読み込むものです。

実装方法

方法1:プラグインを使う

以前の記事でちらっと書いた「Lozad.js」でも実装できるみたいです。
他には「lazysizes」や「yall.js」などがあります。
遅延読み込みの仕組みはプラグインごとで異なりますので、使う前に知っておきたいです。

方法2: Chromeloading 属性を入れる

Chromeがネイティブlazy-loadをサポート、JSなしで画像を遅延読み込み可能に – 海外SEO情報ブログ

Chromeでは img 要素にloading 属性を入れるだけで遅延読み込みになるようになっています。

3種類の値を loading 属性に設定できます。

● loading="lazy": lazy は lazy-load を必ず適用させます。Viewport(スクリーンに見えるエリア)に画像が近づくと画像を読み込みます
● loading="eager": eager は lazy-load を適用せずに、ページのロードと同時にコンテンツを読み込みます
● loading="auto": auto は lazy-load するかどうかの判断をブラウザに任せます。
loading 属性の値が設定されていないとき (loading 属性だけのとき) は、loading="auto" が適用されます。

他のブラウザも対応できるようになってほしいところです。

WordPressの5.5場合、遅延読み込みが標準

htmlの widthheight 属性がついている画像には自動的に loading="lazy" が入る仕様になったそうです。

画像の遅延読み込みが標準機能に【WordPress5.5の新機能】

たしかにWordPressのページのimgタグを見てみると入っている...widthheight 属性には元画像のサイズが入っています。

話は戻りますが、これでレイアウトシフトが起こっていなければhtmlでimg要素にwidthheight 属性を入れた方がいいことになります。
(ざっと検証した感じでは、がくんとなっていないようです...!)

その他WordPressが自動で入れてくれる srcsetsizes 属性などもちゃんと理解していないので、いつか知りたいです。
WordPressが生成したコードをもとにあれこれ勉強するのもいいかと思います。

読み込み速度と見た目を考慮した遅延読み込み

人がいいなと思うページを検索上位に上げたい、というのがGoogleの目指すところらしいです。
見出しに挙げた、早く、かつ自然なページ表示が閲覧者の理想だと思いますが、それに近づけるための方法を調べました。

方法1:画像が読み込まれる前にダミー画像を用意しておく

ダミー画像だったり、プレースホルダー画像と呼ばれています。 真っ白なところに突然画像が表示されるよりは、見た目がユーザビリティにもよいということで、先に容量の小さい画像を表示させておく方法です。

オリジナル画像を小さくして引き伸ばしてぼかした画像をはじめに表示させ、オリジナル画像読み込みのタイミングで差し替えます。

フェードしながら画像を遅延読み込みする機能を実装する方法 | 株式会社LYZON

方法2:ダミー画像なし

プログレッシブJPEGでWEBパフォーマンスを向上させるアイデア

1つのオリジナル画像を段階的に読み込むということで無駄は少なく感じますが、難しそう。

ベースラインJPEGプログレッシブJPEG

JPEGには2つのモードがあります。

通常がベースラインで保存されています。Photoshopで保存時にプログレッシブで保存できます。

f:id:yokoyoko_115:20210105130650p:plain

たしかにありますね。

プログレッシブモードの方が、ベースラインよりも容量が若干小さいようです。
表示のされ方も違うので、2つのJPEG画像の表示を見ると「ああ見たことあるー!」と思いました。

最後に

ページ表示の速度改善はアプローチが様々で、Search ConsoleやPageSpeed Insights の言われるがままにあれもこれもと改善を試みると終りが見えません。

ただ、最適な書き方を知っておくのは大事だと思うので、Googleの示す数字に固執せずに、気になったら都度少し対策、を心がけたいと思います。

Interseprtion Observerを解読する

ちゃんと理解していないのに使ってしまいました...Interseprtion Observer。

このまま年を越すわけにはいかないと思ったので、2020年の力試しとしてまとめます。

2020年最後の記事です。

Interseprtion Observerとは

とてもわかりやすく、詳しく書かれているので、こちらを見て分かる方は十分です。

JSでのスクロール連動エフェクトにはIntersection Observerが便利 - ICS MEDIA

サンプルコードと動きの概要

上記記事から引用させていただきます。
文字通り「解読」なのでこの詳しい記事をさらに細かく見ていきます!

JavaScript

// 今回の交差を監視する要素
const boxes = document.querySelectorAll(".box");

const options = {
  root: null, // 今回はビューポートをルート要素とする
  rootMargin: "-50% 0px", // ビューポートの中心を判定基準にする
  threshold: 0 // 閾値は0
};
const observer = new IntersectionObserver(doWhenIntersect, options);
// それぞれのboxを監視する
boxes.forEach(box => {
  observer.observe(box);
});

/**
 * 交差したときに呼び出す関数
 * @param entries
 */
function doWhenIntersect(entries) {
  // 交差検知をしたもののなかで、isIntersectingがtrueのDOMを色を変える関数に渡す
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      activateIndex(entry.target);
    }
  });
}

/**
 * 目次の色を変える関数
 * @param element
 */
function activateIndex(element) {
  // すでにアクティブになっている目次を選択
  const currentActiveIndex = document.querySelector("#indexList .active");
  // すでにアクティブになっているものが0個の時(=null)以外は、activeクラスを除去
  if (currentActiveIndex !== null) {
    currentActiveIndex.classList.remove("active");
  }
  // 引数で渡されたDOMが飛び先のaタグを選択し、activeクラスを付与
  const newActiveIndex = document.querySelector(`a[href='#${element.id}']`);
  newActiveIndex.classList.add("active");
}

これはスクロールに合わせて目次の見出しに背景色がつくといったものです。
簡単にHTML+CSSの様子を表すと、こうなります。

f:id:yokoyoko_115:20201223005340j:plain

白い部分がビューポート(ディスプレイ)です。
#indexList というところが目次です。

.box を監視して、ビューポートに表示されるとその .box に紐付いた目次の見出しに.active のクラスが付きます。

解読

まとまりごとに見ていきます。

// 今回の交差を監視する要素
const boxes = document.querySelectorAll(".box");

const options = {
  root: null, // 今回はビューポートをルート要素とする
  rootMargin: "-50% 0px", // ビューポートの中心を判定基準にする
  threshold: 0 // 閾値は0
};

監視要素の.boxboxes に入れる。
querySelectorAll メソッドは指定したセレクタのHTML要素(NodeList)を取得します。
boxesを console.log(boxes) とすると、

NodeList(4) [div.box, div.box, div.box, div.box]

などと出てきます。

そして options というオブジェクトを作る。
{} で囲まれているのでオブジェクトです。

ここまでは大丈夫です。
次のまとまりを見ます。

const observer = new IntersectionObserver(doWhenIntersect, options);

new でこれも IntersectionObserverのオブジェクト、observer というインスタンスを作っています。

ここでIntersectionObserverのオブジェクトって何?となりました。

IntersectionObserverはコンストラクター

調べていくと、「IntersectionObserverはコンストラクター」だそうです。

コンストラクター(関数)
new式を使用して新規オブジェクト(インスタンス)を作成する関数。

そういう関数があらかじめ用意されているようです。
これがいわゆる「API」ということでしょうか!

Web API の紹介 - ウェブ開発を学ぶ | MDN

クライアントサイドJavaScriptとはブラウザで動くJavaScriptのことですね。

そのうちのAPIは以下の2つに分けられるとあります。

  • ブラウザ API
     ┗ ブラウザに組み込まれているもの。 ←IntersectionObserverはこっち?
  • サードパーティ API
     ┗ デフォルトではブラウザに組込まれていない。Twitter APIなど

Web APIとしてこちらにもIntersectionObserverが載っていました。

Web API | MDN

Web API は通常 JavaScript とともに使用されますが、常にそうとは限りません。

意味深ですね。他の言語でもWeb API が使われることがあるみたいです。

IntersectionObserver

IntersectionObserver - Web API | MDN

Intersection Observer API - Web API | MDN

苦手意識のあるAPI、また少し分かってきた気がします。
ひとくくりにするにはその種類が多いですね。

IntersectionObserver() の中身を見てみると、doWhenIntersect がコールバック関数で、options が監視範囲の設定値です。

コールバック関数の中身はそのさらに下に書かれているので今は置いておいて...。

// それぞれのboxを監視する
boxes.forEach(box => {
  observer.observe(box);
});

監視対象の .box 要素をループ処理しています。

ここでforEachについて調べました。

JavaScriptでforEachメソッドを使う方法【初心者向け】 | TechAcademyマガジン

forEachはArrayオブジェクトに実装されたメソッド

配列もオブジェクトなのでメソッドがあります。書き方は下記です。

配列.forEach( コールバック関数による処理 )

ここでもコールバック関数!

box => { observer.observe(box); }

この部分、アロー関数で書かれていますが、

function(box) {
  observer.observe(box);
}

と同じです。box.box の各要素です。

observeメソッド

このはたらきは

IntersectionObserver が対象の要素を監視するよう命じます。

だそうです。

observer.observe(box); は、observerというオブジェクトに対してobserveメソッドをあてています。名前が一緒でややこしいですね。
引数に対象の要素を入れています。

つまりは「IntersectionObserver が各 .box 要素を監視する」ということですね。

/**
 * 交差したときに呼び出す関数
 * @param entries
 */
function doWhenIntersect(entries) {
  // 交差検知をしたもののなかで、isIntersectingがtrueのDOMを色を変える関数に渡す
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      activateIndex(entry.target);
    }
  });
}

ここで IntersectionObserver() のコールバック関数が出てきました。
そしてまたforEach。
なぜforEachを使っているのかは、参考本ページに書かれていました。

doWhenIntersect(entries) と引数を設けています。
ここには、doWhenIntersect が発動するタイミングで、監視している要素が入ってくるのだと思います。

コールバックは、入力引数として交差したすべての閾値を示すIntersectionObserverEntry オブジェクトの配列を、また参照としてIntersectionObserver オブジェクト自身を受け取ります。

ちょっと違いました^^;
IntersectionObserverEntry オブジェクトがよく分かりません。

閾値のリスト内のそれぞれの項目は、通過した閾値を説明するIntersectionObserverEntry オブジェクトです。つまり、それぞれの項目は指定された要素がルート要素とどれだけ交差したのか、要素が交差したと言えるのかどうか、推移が発生した方向を示します。

console.log(entries) とすると、閾値に指定している(今回はthreshold: 0)、交差のタイミングで表示されました。

分かったような気がします。大事なオブジェクト...!

isIntersectingプロパティ

監視対象が見えるようになったか、見えなくなったかを判断します。
entry.isIntersectingtrue なら見えるようになった
false なら見えなくなった

です。
(見えている状態が継続されている場合はtrueなのでしょうか)

要素が見え始めた場合に activateIndex という関数に entry.target という引数を渡しています。

targetプロパティ

先程の console.log(entries) のtargetプロパティを見てみると div.box とありました。

このあたりの細かい説明はあまり見つからず...「targetプロパティ」は広くいろいろなところで同じようにセレクタを値に持っているのかもしれませんね。

文章にすると「閾値の交差時に監視対象の要素が見えたら、次の関数を実行する」でしょうか。

/**
 * 目次の色を変える関数
 * @param element
 */
function activateIndex(element) {
  // すでにアクティブになっている目次を選択
  const currentActiveIndex = document.querySelector("#indexList .active");
  // すでにアクティブになっているものが0個の時(=null)以外は、activeクラスを除去
  if (currentActiveIndex !== null) {
    currentActiveIndex.classList.remove("active");
  }
  // 引数で渡されたDOMが飛び先のaタグを選択し、activeクラスを付与
  const newActiveIndex = document.querySelector(`a[href='#${element.id}']`);
  newActiveIndex.classList.add("active");
}

これは読めました。
目次に対して、先にactiveクラスを外してから、該当の要素にactiveクラスを付けています。

以上です!

Lozad.jsについて

こちらのプラグインの中でInterseprtion Observerが使われているということなので調べました。

IntersectionObserveの遅延読み込みライブラリのLozad.jsを紹介する - Qiita

使いやすそうですね。Interseprtion Observer を理解した上で使うならいいと思いました。

最後に

JavaScriptはまだまだ1文ずつ分解して読んでいかないと分からないところがあります。
謎のプロパティ、引数が出てくると心が折れそうになりますが、調べれば正体が分かったので、根気よく解読していこうと思います。

アロー関数とコールバック関数に慣れなくては。

***

2020年に始めたこのブログも何とか1年続けられました。奇跡!
後半息切れしましたが、2021年もマイペースに書いていきます!

JavaScriptの歴史をまとめてみる

まだまだJavaScriptの基本やNode.jsについて抑えておこう!ということで、こちらの動画を見てJavaScriptの歴史を自分なりにまとめてみました。

【モダンJavaScript #2】歴史から学ぶJavaScript前編。ECMAScript、CommonJS、モジュール、名前空間を知ろう【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #3】歴史から学ぶJavaScript後編① Node.jsとパッケージ管理システムnpm【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #4】歴史から学ぶJavaScript後編② IIFE・AMDモジュールとブラウザ向けパッケージ管理システムBower 【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #5】歴史から学ぶJavaScript完結編 バンドル・コンパイルを知る。Browserify, webpack, Babel【フロントエンドエンジニア講座】 - YouTube

素晴らしい動画をありがとうございます!!

☆私の解釈が間違っている可能性もあるので、正しく知るには動画を見ることをおすすめします!

また最近でこんな記事も見つけました。

プログラミング初心者のための JavaScript と Node.js の歴史、それを踏まえた勉強方法

用語など所々難しく感じましたが、JavaScriptは色々な人に使われていて、そのためちゃんと新しく正しい記事を探すべきであることが分かりました。

ざっくりしたJavaScriptの歴史の流れ

動画では4回に分けられていたので同じく分けました。

  1. JavaScriptの誕生
  2. Node.jsの誕生
  3. ブラウザ側でのモジュールの模索
  4. ブラウザJSの進化

サーバーとブラウザ、それぞれでJavaScriptが使われていくようになるのですが、ブラウザのJSは、しばらく使いづらい状況が続いていました。
そこでコードを事前に変換する という発想の転換によって、とても便利に使いやすくなりました。

さらに大事なこととして以下が挙げられていました。

・ JavaScriptの歴史のお話では「ブラウザとモジュール」というのが大きなテーマ
・ プログラミング用語はコンテキスト(背景)、言語、人、ツールによって違う意味で使われる。

用語の定義については、以前引っかかった「コンパイル」もこの類ですね。 今回は「モジュール」と「パッケージ」の違いでもやもやする予感です。

以下長くなりますが文字に起こしました。

1. JavaScriptの誕生

Natscapeのブラウザ(Netscape Navigator)で使われたのが始まり。 もともとは「LiveScript」。
当時注目されていたJavaにあやかって「JavaScript」に名称変更した。

IEでも搭載される

それぞれのブラウザに合わせたJavascriptを作らなくてはならず大変。
統一させたい、と考える。

ECMAScript(エクマスクリプト)の誕生

JavascriptECMA International(標準化団体)に登録された。仕様を一つに統合した。

☆ES(←きっと「ECMAScript」の略)は毎年リリースされる。現在はES[20xx]という表記。

ECMAScript
JavaScriptの中核となる言語仕様のこと。
いろいろな実行環境(サーバー:Node.js、ブラウザ間)でも共通の動作のみが定義されているJavaScript

☆といってもそのまま使えるわけではなく、環境によってはコンパイルしたりする必要がある(後述)。

不人気の後、大人気!

JS起因のクラッシュ、悪用ウィルス、不快なアニメーションなども多く、機能の使用をオフにする人もいた 。

  • GoogleMapsがAjaxを利用 :非同期通信で画面が一瞬白くなったりしない
  • jQueryの誕生:ブラウザ間の差異を吸収できて便利

これらの影響で人気になる。

Ajax(Asynchronous JavaScript + XML)について
初心者目線でAjaxの説明 - Qiita

サーバーサイドのJavascript

サーバーサイドでもJavascriptを作ろう、ということで「ServerJS」というプロジェクトが立ち上がる。

たくさんのAPIを作る必要がある

「CommonJS」へ名称変更(プロジェクト名の変更)
たくさんのAPI仕様が作られていく

API
Application Programming Interface
「アプリケーション、ソフトウェア」と「プラグラム」をつなぐもの

JavascriptAPIを作る」とはどういうことなのかなぁと引っかかりましたが、先のAjaxの参考ページにもあったように、Ajaxの機能を支えるXMLHttpRequestDOMAPIということなので、同じようなものを作ろうとしていたのだろうと考えました。
インターフェースなのでJSと外との窓口を増やす、といったイメージでしょうか。

モジュールAPI
CommonJSで作られたAPIのうちの1つ。モジュールを使う。

モジュール
ただのファイル。1つのスクリプトは1つのモジュール。
exportとimportを使用して機能をやり取り、あるモジュールの関数を別のモジュールから呼び出したりすることができる。
例)変数をexportして、別ファイルでimport(require)して使うことができる

Javascriptの課題

名前空間が一つしかない

変数や関数の命名が被ると上書きしてしまう。バグが発生しやすい。
例)あるjsファイルを3つに分けてhtmlファイルでa、b、cと順に読む

//a.js
var foo = 123;

//b.js
var foo = "foo";

//c.js
foo * 10; // NaN  ←変数fooの値は"foo"に上書きされている

let を使っても上書きされます。
const を使って同じ変数名にすると、この場合エラーになります。

サーバーではモジュールを使って解決。ブラウザでも使えるようにしたい。

Javascriptのモジュールは1ファイル単位でスコープ(“よそはよそ、うちはうち”)がかかっている。ファイル内の変数や関数は外部に影響しない 。

依存関係がある

読み込みの順番がある。
例)jQuery→jQueryUIの順で読み込まないとバグが発生する

2. Node.jsの誕生

モジュールの仕組みを持っている。
最初はCommonJSのモジュールAPIに準拠している(requireとexportをつかったもの。言い方:「CommonJS形式のモジュール」)

CommonJS(プロジェクト)は機能しなくなり、 Node.jsが独自の進化を遂げる。現在はモジュールの仕組みもCommonJSとは違うものがある。

Javascriptは複数の形式(仕様)のモジュールがある。

npmの誕生

モジュールのおかげで名前空間の問題が解決し、機能を細分化することができた。
すると、機能を他のプロジェクトでも使い回すようなる(共有)。
(他のサーバーサイド言語ではすでに実現されている)

npm誕生

npm(Node Package Manager)
Node.jsのパッケージ管理システム

パッケージ
package.jsonで記述されたファイルやディレクトリのこと。
共有したい機能をまとめた1つの単位。1ファイルの場合もあれば、ディレクトリの場合もある。

パッケージ管理システム
パッケージのバージョンを管理したり、共有するためのシステム。

はたらき

  1. リポジトリの購読
    ローカル環境にインストールしたパッケージを更新できる。パッケージを検索できる
  2. パッケージのインストール、削除
    パッケージを指定してローカルにインストールできる。削除もできる
  3. 依存関係の解決
    パッケージに必要な別なパッケージを自動的にインストールや更新することでがきる
  4. 設定管理
    設定を書くことで、1.2.3を自動で行える。毎回手動でパッケージを入れたりする必要がなくなり、チームでの環境を簡単に揃えたりすることができる

☆パッケージの依存関係を視覚化されているサイト
http://npm.anvaka.com/#/

☆npmのサイトの、パッケージのメニュー「Dependencies」では依存関係にあるパッケージが載っている。(Dev Dependenciesはまた別)

☆なるべく依存関係の少ないパッケージを選ぶと良い。

サーバーサイドJSの準備が整う

名前空間 → モジュールで解決
依存関係の問題 → npmで解決
有名企業も採用するように(UberNetflixなども!)

3. ブラウザ側でのモジュールの模索

モジュールっぽい仕組みはサーバーサイドJavascriptよりも前にあった。4パターン。

IIFE(即時実行関数式)形式

(function() {
  var foo = "foo";
})();
foo; // foo is not defined  即時関数の外ではfooは未定義

関数を使って、擬似的にプライベートな空間を作り上げている。

それだけでは不十分 。 言語仕様としてのモジュールではないので、名前空間の問題も完全に解決されていない。

AMD & Require JS誕生

AMD:モジュールの仕様(形式)
ブラウザ環境での実行を考慮し、依存関係の解決及び遅延ロードに対応した仕様

Require JS:AMDを実装しているもの

ブラウザでもモジュールが実現。依存関係も解決することができる。

AMD形式

define(["moduleA", "moduleB"], function(fnA, fnB) {
  // returnしたものがpublic(外部に出す)
  // returnしなければprivate
  return function() {};
});

☆moduleAとmoduleBにjQuery、jQueryUIを入れて開発、モジュールを作る、ということもできる。

次に欲しいのはブラウザ向けパッケージ管理システム

Bower誕生

Bower(バウアー)
クライアントサイド(ブラウザ)開発向けのパッケージ管理システム。
npmと似たようなことができる 。 ほとんどのBowerのパッケージはIIFEモジュールか、AMDモジュールを利用している。

ブラウザJavascripの落とし穴

AMD形式のモジュールは、サーバー側との互換性がない。構文がCommonJS形式と比較して冗長。メンテナンスも大変。

Bowerは、パッケージの依存関係の定義をユーザーが手動で定義する必要がある。 同一ページ内にある同じパッケージの異なるバージョンをサポートしていない 。 例)jQueryの1系と2系を同一ページで一緒に使えない

モジュールまとめ

  • IIFE形式(欠点あり)
  • AMD形式(欠点あり)
  • CommonJS形式 (Node.jsで成功)

UMD形式もある(パッケージを外部に公開するときの設定の話)

ブラウザJS、考え方を変える

CommonJS形式で書かれたものを事前にブラウザ形式に変換する
書いたコード(開発時のコード)と(ブラウザで)動くコードが違う。

事前にブラウザ向けに変換する方法

Bundle
Bundleを使うと...

  1. 開発時はCommonJSモジュールで開発
  2. モジュールの依存関係を解決して1ファイルに変換(バンドル) → jsファイルになる
  3. 2でできたファイルをscriptタグで読み込む

☆CJS(CommonJS)モジュールだけではなく、CSSや画像やいろいろなものをBundleすることができる。

☆設定によって複数ファイルにバンドルすることができる。

Browserify(ブラウザリファイ)
CommonJS形式に書かれたものをブラウザ向けにバンドルするツール。 CJS形式モジュールをバンドルする。

Browserifyを使うと、ブラウザでもNode.js同様requireを使うコードが使用できる
CommonJS形式のモジュールが使えるようになる。

npmのパッケージがブラウザ向けに移植される

ブラウザでもnpmが主流に!

もともとnpmはCommonJS形式で書かれたパッケージが多く、ブラウザでは使えなかったが、Browserifyでブラウザ向けに変換できることで、ブラウザでもnpmが使われるようになった。

webpack
新たなバンドルツール(「モジュールバンドラー」と呼ばれる)。
Browserifyよりも高機能(chunk(チャンク)という単位で区切ることで最初のロード時間を短縮できる)。
主にJavascript向けだが、対応するローダーがあればHMTML、CSS、画像などのフロントエンドのアセット("もの")もバンドルすることができる。

☆バンドル前のファイルはブラウザで読み込めない拡張子のものがある(.sass、.cjs、.hbs)

☆バンドル前のファイルは依存関係にあるが、バンドル後のファイルは依存関係がない

ES Modules(ESM)の誕生

言語仕様としてのモジュールが欲しい。
今まで出てきたモジュールは、自分たちでどうにかして作ったモジュールっぽい仕組み(独自仕様)だった。

CJSではrequireを使っていたところ、ES Modulesではimport構文を使う(ES2015)

webpackがES Modulesに対応(ネイティブサポート)

ES Modulesはまだほとんどのブラウザでサポートされていなかった。モジュールバンドラーはまだ必要。
でもES Modulesで書きたい。

☆「ネイティブサポート」とは、webpackはローダーがなくてもES Modulesを読み込めるようになった、ということ

☆後に「Parcel(パーセル)」というモジュールバンドラーも出てくるが"webpack1強"に変わりはない

☆現在のES Modulesサポート状況
webpackを通さなくても、IE以外のモダンブラウザとNode.jsのVersion12系以上では標準で使用可能

Compile
Compileを使うと...

  1. 開発時はブラウザでは動かないけど、開発に便利な機能を使ってコードが書ける
  2. 書いたコードをブラウザで動くように変換する(コンパイル
  3. 変換したコードをscriptタグで読み込む

バンドルは依存関係の解決に焦点を当てていたが、コンパイルは純粋に便利な機能をJSに変換する。

ES2015のたくさんの仕様

モジュール、let、const、class、Promise、アロー関数、分割代入、スプレット構文、テンプレート文字列などなど。
IEではすぐには使えないが、コンパイルで解決!

Babel(6to5 ←最初の名称)誕生

Babel
ES2015などで書かれたコードを従来の環境でも動くように古いJavascriptに変換するコンパイラ

☆似た言葉で「トランスパイラ」があるが、Babelのサイトには「コンパイラ」とある。

便利なパッケージが流行る

パッケージ

  • React(.jsx)
  • Vue(.vue)
  • TypeScript(.ts)

これらはコンパイルしてjsファイルにして使う。

パラダイムシフトが起こった

事前に変換というパラダイムシフト(考え方が大きく変わること)が起こり、現在は段々とjQueryが使われなくなっってきている。

最後に

後半駆け足になってしまいましたが、字が多すぎ。図を入れたかった...。

ここまでまとめると、モジュールの進化がすごいことが分かりました。

モジュールとパッケージの関係も、モジュール(機能)がセットになったものがパッケージかな、と少し分かりました。

といっても、未だ「ブラウザでパッケージを使う」機会に遭遇していないので、ピンときていません。
Node.js同様、コマンドを叩いたりするのでしょうか。

早くReactが分かるようになりたい...とじりじりしていますが、 少しずつ前へ進みたいと思います!

【css】line-heightの使い方

テキストのすき間問題。見て見ぬふりしてきたシリーズの1つです。

vertical-align も気になっているのですが、今回は line-height を見つめ直す機会があったのでおさらいします。

まずこちらの記事を読んで「なるほど」と理解してから考えます。

【CSS】line-heightで行間を調整する方法:おすすめの値は?

覚えておきたいこと

line-height の単位は付けないほうが使いやすい

emや%よりも「単位なし指定」がオススメです。なぜかというとemや%だと親要素で計算された行高が、子要素にそのまま引き継がれてしまうからです。つまり、親要素のフォントサイズが40px、子要素のフォントサイズが20pxの場合にも、子要素には親要素と同じ行間が適用されてしまうのです。 一方で単位なし指定の場合、子要素のフォントサイズに応じて行高を計算し直してくれます。

てっきり単位なしは em% と同じ意味だと思っていました(この2つは同じ、だと思います)。

今までのコード書き直したい...。

line-height はblock要素に効く

これはinline-block でもダメでした。 今回検証したところ、span要素には効きませんでした。
確かに文章の途中で行間が変わる、というのは考えにくい事象ですね。

レイアウトしたもの

こんな感じの、1行目が大きい文字で、2行目が小さい文字のレイアウトです。
いろいろ書き方はあると思いますが、今回はp要素の中にspan要素で小さい字を入れて改行させました。

f:id:yokoyoko_115:20201119001000j:plain

この図が今回のまとめです。

当初大きい文字(1行目)と小さい文字(2行目)の行間がものすごく空いてしまい、line-height: 1em だ!line-height: 0だ!とあれこれやっていましたが、改めてちゃんと調べたらスッキリしました。

おまけ

ちなみに、line-height: 0 ですと要素の高さが0になってしまうようです。

テキストをドラッグして選択したときの高さというのは要素の高さとはまた少し違い、line-heightの高さなのかな?と思いました(line-height: 0 は最低限1文字の高さの範囲で選択できます)。
そもそもインライン要素の高さとは...。 このあたりややこしそうです。

See the Pen line-height検証 by yokoyoko (@yokoyoko_code) on CodePen.

正規表現チェックツールの使い方

ごく稀に正規表現を書くことがあり、その度に正規表現の書き方を調べています。 時間のないときはお手上げです...。

そんな時にこちらのツールを教えていただきました!

正規表現チェッカー | WEB ARCH LABO

次回以降、こちらのツールの使い方を思い出せるようにメモします。

正規表現チェッカーの画面の使い方

正規表現もよく分かっていないと、この画面だけを見ても使い方が分かりませんでした。

使い方
① 渾身の正規表現を「正規表現」の欄に入力する
② ①にマッチするであろう文字列を「検証対象文字列」の欄に入力する(改行して何パターンも文字列を検証できる)
③ マッチすると「結果」欄に②の文字列が赤く表示される

例)
f:id:yokoyoko_115:20201024005909p:plain

こんな感じで使いました。 「正規表現」の欄に右の正規表現の表を見ながら試行錯誤して入力して、ひたすらチェックするといった使い方になりそうです。

またこのサイトでは「HTMLエスケープ」という、HTMLエスケープされた文字列を返してくれるツールもあります。便利です。

正規表現とは

そもそもですが調べてみました。

サルにもわかる正規表現入門

端的に言えば、「いくつかの文字列を一つの形式で表現するための表現方法」です。

なるほど。

^$ などの特殊文字正規表現ではメタ文字というそうです。

正規化とは

こちらもよく聞く単語だったので調べました。

https://wa3.i-3-i.info/word11632.html

データとかを使いやすいように整理したり変形したりすることです。

正規表現と関係があるかと思いましたがそうでもないようです。
(同じ「正規」と付くだけあってそこまで遠くはなさそうですが...)

.htaccessでリダイレクトの方法

ちなみに今回は.htaccessでリダイレクトの設定をしました。

これもメモ程度にざっくり書くと、

RewriteRule サイト内の対象ページ リダイレクト先 [R=301,L]

です。正規表現を使って書くことができます。

頭に RewriteRule が付き、最後は [R=301,L] などで終ります。

また、「対象ページ」に書いた (.+) など () で囲った部分は、「リダイレクト先」に$1$2$3 と書いて渡すことができます。

例)

RewriteRule ^blog/(.+)cat/(.*)$ https://%{HTTP_HOST}/blog/cat/$2 [R=301,L]

これで
https://example.com/blog/postcat/hoge

https://example.com/blog/tcat/hoge
リダイレクトします。
$2 には (.*) が渡ります。

.htaccessの書き方は勉強しよう!

と、自分に言い聞かせています。

.htaccessではいろいろなことができますが、1歩間違えればサイトにアクセスすらできない、恐れ多い印象を持っています。
難しく感じてしまうのは正規表現をつかった処理が出てくるから、というのもあると思います。
少しずつ理解していきたいです。

正規表現がある程度スラスラ書けるようになると、いろいろな場面で役立ちそうなので、 こういったツールを使って正規表現に慣れていきたいです。