Web開発で使用する画像フォーマットの特性について

Web開発において、適切な画像フォーマットを選択する際の基準や考慮するべき点についての参考をまとめました。

WEB開発において一般的に使用する画像フォーマットの種類

画像形式 WebP AVIF JPEG PNG GIF SVG
拡張子 .webp .avif .jpg .png .gif .svg
圧縮方法 非可逆圧縮(ロッシー)/可逆圧縮(ロスレス) 非可逆圧縮(ロッシー)/可逆圧縮(ロスレス) 非可逆圧縮(ロッシー) 可逆圧縮(ロスレス) 可逆圧縮(ロスレス) 可逆圧縮(ロスレス)
透過 × ×
アニメーション × ×

可逆圧縮は保存を繰り返しても画質が劣化しません。それに対して非可逆圧縮は保存するごとに画質が劣化します。
WebPやAVIFは可逆圧縮・非可逆圧縮の両方に対応しているのでどちらかを選択可能です。
非可逆圧縮にする方が軽くなります。
PageSpeed Insightsでは「画像を効率的にエンコードする」事が推奨事項であり、その為に次世代フォーマットの画像提供を推奨しています。

用途に応じて、一般的に推奨される画像フォーマット

WebP

用途: Webページの高速読み込みを重視する場合。写真やイラストにも使えます。
利点: JPEGとPNGの利点を組み合わせたようなフォーマット。高い圧縮率と高品質な画像が特徴です。透明背景やアルファチャンネル、アニメーションもサポート。
注意点:2023年現在、WebPはWeb上で画像を効率的に圧縮するためのフォーマットとして広く使用されています。WebPは一般的な画像フォーマット(JPEGやPNG)と比較して、より小さなファイルサイズで美しく表示できます。これにより、ウェブページの読み込み速度を向上させることができます。
ただし、すべての画像をWebPに変換する際にはいくつかの点に注意する必要があります。
WebPはすべてのブラウザで完全にサポートされているわけではありません。一部の古いブラウザやプラットフォームでは、WebP画像が正しく表示されない可能性があります。したがって、対象とするユーザー層のブラウジング環境に応じて、適切な対応を検討する必要があります。
WebP画像をサポートしていないブラウザや環境のユーザーにも適切な画像を提供するために、フォールバックの画像(通常はJPEGやPNG)を用意することが重要です。
現在のサポート状況
https://caniuse.com/?search=webp

AVIF

用途: AVIFはHDR(ハイダイナミックレンジ)画像をサポートしており、明るい風景の視認性が高いため、雲や太陽といった高輝度の映像を表示する際に、向いております。
利点: AVIFは非常に高い圧縮効率を提供します。同じ画質であっても、JPEGやPNGと比較して小さなファイルサイズで画像を保存できます。特に、高解像度の画像や複雑なシーンにおいて効果があります。
注意点: AVIFのブラウザサポートは進展していますが、まだ完全なサポートが得られないのが現状です。一部の古いブラウザやプラットフォームでは、AVIF画像が正しく表示されない可能性があります。したがって、対象とするユーザー層のブラウジング環境に応じて、適切な対応を検討する必要があります。
AVIF画像をサポートしていないブラウザや環境のユーザーにも適切な画像を提供するために、フォールバックの画像(通常はJPEGやPNG)を用意することが重要です。
現在のサポート状況
https://caniuse.com/?search=AVIF

JPEG (Joint Photographic Experts Group)

用途: 写真やイメージで色合いやトーンが重要な場合。
利点: 圧縮率が高く、自然写真を表示する場合に特に適しています。見た目は遜色なくPNGファイルよりファイルサイズが比較的小さくなります。
注意点: 透明な背景やアルファチャンネルをサポートしません。

PNG (Portable Network Graphics)

用途: 透明な背景や図形、アイコンなど。イラストやグラフィックスに適しています。特に、文字や図形などのような輪郭のハッキリした絵の画像では、JPEGよりも圧倒的に高画質です。
利点: 透明な背景やアルファチャンネルをサポート。非圧縮または可逆圧縮で保存され、高品質な画像が得られますが、ファイルサイズは大きめです。

GIF (Graphics Interchange Format)

用途: 簡単なアニメーションや低色数のイラスト。
利点: 複数のフレームを含むアニメーションに適しています。ただし、色数が制限されるため、写真には不向きです。

SVG (Scalable Vector Graphics)

用途: ベクター形式のグラフィックスやアイコン。多様な解像度に適応するのに便利。ベクター形式とは、点の座標やそれを結ぶ線を数値データで記録・再現する画像方式です。
利点: ベクター形式のため、拡大・縮小しても品質が損なわれません。線や面の輪郭がはっきりしたロゴやイラストに特化しています。写真には適していません。フォントにも使えます。

次世代フォーマット 2023年現在のAVIFとWebPの比較

圧縮効率と画質

AVIF
AVIFは高い圧縮効率と優れた画質を提供することで知られています。従来の画像フォーマットよりも小さなファイルサイズで、高解像度の画像を保持する能力があります。
WebP
WebPも優れた圧縮効率と画質を提供しますが、AVIFほど高い圧縮率での画質維持には若干劣る可能性があります。

ブラウザサポート

AVIF
AVIFのブラウザサポートは2023年時点でも進展していますが、まだ完全なサポートが得られるわけではありません。一部の主要なブラウザはAVIFをサポートしていますが、すべてのブラウザで問題なく表示されるわけではありません。
WebP
WebPは2023年でも広くサポートされており、多くの主要なブラウザで問題なく表示されると考えられています。(一部の古いブラウザやプラットフォームを除く)

エンコードとデコードの効率

AVIF
AVIFのエンコードやデコードは計算リソースを必要とするため、一部の環境や古いデバイスではパフォーマンスの問題が発生する可能性があります。
WebP
WebPのエンコードとデコードは効率的であり、一般的に広範囲な環境でスムーズに動作します。

フォーマット選択の考慮事項

AVIFとWebPの選択は、プロジェクトの特定のニーズに基づいて行うべきです。AVIFは高い圧縮率と画質を提供しますが、ブラウザサポートが限られるため、主要なブラウザの利用者をカバーすることができるか検討が必要です。一方、WebPは広範囲なブラウザサポートを持ち、多くの場合に適しています。
総括すると、AVIFとWebPはどちらも高性能な画像フォーマットであり、プロジェクトの要件やターゲットユーザー層に応じて選択する価値があります。AVIFは圧縮率と画質において優れていますが、ブラウザサポートの限定があるため、現在はWebPのほうがより広範囲な利用ができるといえます。

今回は画像フォーマットの特性についてでした。
次回は次世代フォーマットの書き出しについて書きます。

WordPressが不要なタグを補完するのを止める方法

ワードプレスのブロックエディタが不要なタグを補完する機能は、通常の動作として組み込まれていますが、カスタマイズして無効化する方法があります。
以下の手順に従って、不要なタグの補完を停止することができます。

注意:functions.phpを編集する必要があります。ファイルのバックアップを取っておきましょう。

  1. functions.phpというファイルを探します。ファイルの場所は/wp-content/themes/テーマ名/functions.php
  2. functions.phpファイルをテキストエディタで開きます。
  3. 下記のコードを追加します。
  4. ファイルを保存して、FTPクライアントなどでサーバーにアップロードします。

変換機能自体を停止させたい場合

add_filter('run_wptexturize', '__return_false');

指定した個所で停止したい場合

// タイトル欄
remove_filter('the_title', 'wptexturize');
// 本文欄
remove_filter('the_content', 'wptexturize');
// コメント欄
remove_filter('comment_text', 'wptexturize');
// 抜粋欄
remove_filter('the_excerpt', 'wptexturize');

pタグの挿入を停止させる場合

// タイトル欄
remove_filter('the_title', 'wpautop');
// 本文欄
remove_filter('the_content', 'wpautop');
// コメント欄
remove_filter('comment_text', 'wpautop');
// 抜粋欄
remove_filter('the_excerpt', 'wpautop');

関数を作って細かく設定する

有効はtrue、無効はfalse

function my_tiny_mce_before_init( $init_array ) {
    //グローバル変数の宣言
    global $allowedposttags;
    //エディタのビジュアル/テキスト切替でコード消滅を防止(自動整形無効化)
    $init_array['valid_elements']          = '*[*]';
    $init_array['extended_valid_elements'] = '*[*]';
    //aタグ内ですべてのタグを仕様可能に
    $init_array['valid_children']          = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']';
    $init_array['indent']                  = true;
    //pタグの自動挿入を無効化
    $init_array['wpautop']                 = false;
    $init_array['force_p_newlines']        = false;
    //改行をbrタグに置き換える
    $init_array['force_br_newlines']       = true;
    $init_array['forced_root_block']       = '';
    return $init_array;
}
add_filter( 'tiny_mce_before_init' , 'my_tiny_mce_before_init' );

ACF(アドバンスカスタムフィールド)上記では自動補完止まらない問題

第三引数$formatにfalseを指定すると、フォーマット処理をキャンセルできます。
現在の投稿IDでよければ、第二引数にfalseを設定することができます。

get_field ( "image_field", false, false );

関数を作る

function acf_field_without_wpautop( $field_name ) {

   remove_filter('acf_the_content', 'wpautop');

   the_field( $field_name );

   add_filter('acf_the_content', 'wpautop');
}

function acf_subfield_without_wpautop( $field_name ) {

   remove_filter('acf_the_content', 'wpautop');

   the_sub_field( $field_name );

   add_filter('acf_the_content', 'wpautop');
}

使用方法は

<?php acf_field_without_wpautop('フィールド名');?>

これで、ワードプレスのブロックエディタが不要なタグを補完する機能が無効化されるはずです。

MTで複数サイトの記事の一覧をjsonで出力してjsでhtml整形する方法

Movable Typeを使用して複数のサイトの記事一覧をJSON形式で出力し、JavaScriptを使用してHTML形式に整形する手順です。

通常にHTMLとして複数サイトの記事をまとめて一覧にする為に出力したいサイトIDを指定して記事を出力します。

サイトのIDは

ダッシュボード > システム > サイトで確認できます。

サイトのIDは引っ越しなどで変わってしまうため、最近は構築の時にIDではなくサイト名を変数に入れてサイト引っ越しで変わっても問題なく表示されるように

下記のように変数に格納しています。

<mt:Blogs>

<mt:If tag="BlogName" eq="サイト1"><$mt:BlogID setvar="site_1_id"$></mt:If>

<mt:If tag="BlogName" eq="サイト2"><$mt:BlogID setvar="site_2_id"$></mt:If>

</mt:Blogs>

1. Movable Typeのテンプレートを作成します。

記事一覧を表示するためのテンプレートを作成します。

テンプレート内で必要な情報(タイトル、URL、日付など)を出力するためのテンプレートタグを使用します。

2. テンプレートをJSON形式で出力するように設定します。

Movable TypeのテンプレートでJSON形式を出力するように設定します。

[

<mt:Entries include_blogs="$site_1_id" lastn="0">

  <$mt:EntryDate format="%Y%m%d%H%M%S" setvar="key"$>

  <mt:SetVarBlock name="entries" key="$key">

  {

    "created_at":"<$mt:EntryDate format="%Y.%m.%d"$>",

    "title":"<$mt:EntryTitle$>",

    "url":"<$mt:EntryPermalink$>"

  }

  </mt:SetVarBlock>

</mt:Entries>

<mt:Entries include_blogs="$site_2_id" lastn="0">

  <$mt:EntryDate format="%Y%m%d%H%M%S" setvar="key"$>

  <mt:SetVarBlock name="entries" key="$key">

  {

    "created_at":"<$mt:EntryDate format="%Y.%m.%d"$>",

    "title":"<$mt:EntryTitle$>",

    "url":"<$mt:EntryPermalink$>"

  }

  </mt:SetVarBlock>

</mt:Entries>

<mt:Loop name="entries" sort_by="key numeric reverse">

  <mt:If name="__counter__" le="20">

  <$mt:GetVar name="__value__"$>

  <mt:If name="__last__"><mt:Else>,</mt:Else></mt:If>

  </mt:If>

</mt:Loop>

]

3. JSONファイルとして出力します。

テンプレートのデータを、JSONファイルとして出力します。

Movable Typeの管理画面から、テンプレートの出力先(出力ファイル名)任意のファイル名.jsonに設定します。

4. HTMLファイルを作成し、JavaScriptを使用してJSONファイルを読み込みます。

HTMLファイル用テンプレートにJavaScriptを使用し、JSONファイルを読み込みます。

<script type="text/javascript">

    window.addEventListener('DOMContentLoaded', function(){

    $.getJSON("../2,で作った任意のファイル名.json", function(list){

        for(var i in list){

            var h = '<li>'

                + '<a href="'

                + list[i].url

                + '">'

                +'<span>'

                + list[i].created_at

                +'</span><span>'

                + list[i].title +'</span>';

            $("ul").append(h);

            }

        });

    });

</script>

以上が、ムーバブルタイプを使用して複数のサイトの記事一覧をJSON形式で出力し、JavaScriptを使用してHTML形式に整形する手順です。

具体的な実装には、使用するライブラリや環境によって異なる部分がありますので、適宜調整してください。

ちなみにjsonじゃなければ複数サイトの記事をまとめて出力するのには下記のほうが楽だと思います。

    <ul>
    <mt:Entries include_blogs="$site_1_id,$site_2_id" lastn="20">
        <li>
            <a href="<$mt:EntryPermalink$>">
                <span><$mt:EntryDate format="%Y.%m.%d"$></span>
                <span><$mt:EntryTitle$></span>
            </a>
        </li>
    </mt:Entries>  
  </ul>

MovableTypeで絶対パスをルート相対パスに書き換える

MovableTypeが出力するURLは、絶対パスです。
それをスラッシュで始まるルート相対パスに置換する方法を下記の参考サイトを元にテンプレに反映しました。

タグの、href 属性、src 属性、content 属性の URL にウェブサイトURLが含まれている場合、そのURLの絶対パスの部分を <mt:WebsiteRelativeURL> の値に書き換えします。
<mt:WebsiteRelativeURL>で生成されるURLは下記です。

ウェブサイトの URL を、ホストからの相対 URL で表示します。たとえば、ウェブサイトのサイトURL が http://www.example.com/first-website/ の場合、/first-weblog/ を表示します。

https://www.movabletype.jp/documentation/appendices/tags/websiterelativeurl.html

テンプレートモジュールを作る

テンプレート名:impovRootPath

<mt:SetVars>
  impov_siteURL_regex=/(?!\s*?<link[^>]+?rel="canonical")(.*?<[^>]+?(href|src|content)=")<mt:WebsiteURL>/mig
  impov_siteURL_replace=$1<mt:WebsiteRelativeURL>
</mt:SetVars>

インデックステンプレート、アーカイブテンプレート、コンテンツタイプテンプレートに適用する

テンプレートに先ほど作ったテンプレートモジュールを適用します。
テンプレートのソースを下記のコードで囲みます。

<mt:Include module="impovRootPath">
<mt:Unless regex_replace="$impov_siteURL_regex","$impov_siteURL_replace">
 
//テンプレート本体

</mt:Unless>

再構築すると絶対パスがルート相対パスに置換されています。
canonical属性のついたURLとhref属性の外にあるURLは置換しません。
外部サイトのURLに影響が出ることはありません。

正規表現により、条件に合致する部分のみ regex_replace で置換しています。

ページャープラグインPageButeを使っていると絶対パスに書き換えられてしまう問題

サイト内でどうしても絶対パスが吐き出されてしまうページがあり、他のページと見比べていると、PageButeのタグ内のURLだけ絶対パスで吐き出されてしまっていました。

やってみた解決法

下記のようにPageContents内に<mt:Unless regex_replace=”$impov_siteURL_regex”,”$impov_siteURL_replace”>の記述を書きました。

<mt:PageContents count="10" navi_count="4" abs2rel="1">
<mt:Unless regex_replace="$impov_siteURL_regex","$impov_siteURL_replace">
	<mt:Entries lastn="0">
		<a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a>
	<mt:PageSeparator>
	</mt:Entries>
</mt:Unless>
</mt:PageContents>

無事にルート相対パスに書き換えられました。

MTEntryで複数のカスタムフィールドで絞り込む

表題の件でてこずった件の備忘録です。
MTってそもそもWPよりHOW TOが充実していなくて調べるのに疲れてしまいます。。。
今回はチェックボックスのカスタムフィールド二つのどちらかにチェックが入っていたらその記事を出力しないというものでした。
カテゴリーなら複数条件簡単なんですけどね。

まず結果から言いますと

<mt:entries field:フィールド名1="0"></mt:entries>
//フィールド名1にチェックされていないデータ 実際には出力していない
<mt:entries field:フィールド名2="1" unique="1">
//モディファイヤuniqueでフィールド名1にチェックされていないかつ、フィールド名2にチェックされているデータ
<mt:entrytitle>
</mt:entries>

これで二回フィルタリングされて出力されました。
フィールド名1はチェック無しでなおかつフィールド名2にはチェックが入っている記事のみ出力できます。

つまりフィールド2も=”0”にすれば、どちらにもチェックがされていない記事が出力できます。

<mt:entries field:フィールド名1="0"></mt:entries>
//フィールド名1にチェックされていないデータ 実際には出力していない
<mt:entries field:フィールド名2="0" unique="1">
//モディファイヤuniqueでフィールド名1にチェックされていないかつ、フィールド名2にチェックされていないデータ
<mt:entrytitle>
</mt:entries>

mt:entries field:〇〇
MT公式にはこのモディファイアでは、カスタムフィールドに入力した複数の値を組み合わせたフィルタリング (AND, OR, NOT) を利用できません。
と書いてあるけど複数条件で絞り込む方法は見当たらず。この辺が本当に不親切よね怒
MTはオフィシャルでわからなかったら個人のブログを探す方が探している内容が見つかったりしますねー。

参考にした記事は下記です。
他の方法はうまくいかなかったー。

WordPressのビジュアルエディタとテキストエディタを行ったり来たりしてもaタグが消えないようにする設定


/* エディター切替時のタグ消滅回避 の設定 */
function my_tiny_mce_before_init( $init_array ) {
    global $allowedposttags;
    $init_array['valid_elements']          = '*[*]';
    $init_array['extended_valid_elements'] = '*[*]';
	$init_array['valid_children'] = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']'; //aタグ内にすべてのタグを入れられるように
return $init_array;
}
add_filter( 'tiny_mce_before_init' , 'my_tiny_mce_before_init' );
https://blog.ekaki-j.com/wp-code-disappearance

パラメーター付きリンクから飛んできた時該当のチェックボックスを選択済みにする方法

今回はリンクについているパラメーターのname属性とinputのname属性が一致したらinputにチェックをつけるという方法です。

サイト改修案件でチェックボックスで作られたアコーディオンにidが振られており、外から飛んできたときに該当の箇所がcheckedになりアコーディオンが開くという仕様にする際にやったことをメモしておきます。

今回アコーディオンのcssは割愛しております

リンクにアンカーをつける場合はパラメーターの後につけてください。
例:?test=1&test2=2#hoge

デモ

https://codepen.io/mahyam/pen/ZEpaWxo?test=1&test2=2

js

$(function() {
    var url = location.href; /*サイトのURL取得*/
    var params = url.split('?'); /*URLの?の部分で切り離す*/
    var param = params[1].split('&'); /*URLの?以降のURLを&で切り離す*/
    for(var i = 0; i < param.length; i++) {
/*paramにはURLの?以降のURLを&で切り離した値の配列が入っているその数だけ繰り返す*/
        var vl = param[i].split('=');/*param の配列の値を=で切り離す*/
        $('input').each(function(){
            var name = $(this).attr('name');/*inputのname属性を取得して変数nameに入れる*/
            if(vl[0] == name) {
/*変数vlの[0]には送られてきたリンクで送られてきたname属性,[1]にはリンクで送られてきたvalueが入っていますvl[0] とinputのname属性が一致したら*/
                $(this).prop("checked",true); /*そのinputをcheckedにする*/
            }
        });
    }
});

HTML

<label for="testcheck1">テスト1</label><input type="checkbox" id="testcheck1" name="test" value="1">
<label for="testcheck2">テスト2</label>
<input type="checkbox" id="testcheck2" name="test2" value="2">

MTのカテゴリーアーカイブリストをリンク付きで表示する

テンプレート>テンプレートの種類を選択>記事リストアーカイブ

を選択し新規作成

<mt:entries>
<div>
<h1><$mt:EntryTitle$></h1>
<p><$mt:EntryBody convert_breaks=”0″ remove_html=”1″ words=”100″$>…</p>
<p><a href=”<$mt:EntryLink$>”>つづきを読む</a></p>
</div>
</mt:entries>

一旦保存しアーカイブマッピングの設定が表示されたらカテゴリーを選択して保存する。

アーカイブページはこれで終了。

次にトップページのサイドバーに<$mt:CategoryArchiveLink$>タグを使って各カテゴリーアーカイブページのリンクリストを表示した。

<mt:IfArchiveTypeEnabled archive_type=”Category”>
<mt:if tag=”BlogCategoryCount”>
<mt:TopLevelCategories>
<mt:SubCatIsFirst>
<ul>
</mt:SubCatIsFirst>
<mt:If tag=”CategoryCount”>
<li><a href=”<$mt:CategoryArchiveLink$>”<mt:If tag=”CategoryDescription”> title=”<$mt:CategoryDescription remove_html=”1″ encode_html=”1″$>”</mt:If>><$mt:CategoryLabel$> (<$mt:CategoryCount$>)</a>
<mt:Else>
<li><$mt:CategoryLabel$>
</mt:If>
<$mt:SubCatsRecurse$>
</li>
<mt:SubCatIsLast>
</ul>
</mt:SubCatIsLast>
</mt:TopLevelCategories>
</mt:if>
</mt:IfArchiveTypeEnabled>

最初なぜがうまくカテゴリ―別アーカイブページに飛ぶリンクが生成されなかったが、カテゴリーアーカイブのテンプレートのマッピングを一度削除しもう一度設定して再構築かけたら各カテゴリのアーカイブリンクが表示された。

おそらく作成順序的にトップにタグを先に設置したためマッピングがうまくいっていなかったと思われる。

jsonデータにクラスのついたspanタグを含める場合

トップに書き出されるカテゴリに自動でclass=”〇〇”のついたspanタグを挿入したかったので大外をシングルクォーテーションでくくったら真っ白になってしまいました。

jsonはjsのようにシングルクォーテーションは使えないらしいです。

ダブルクォーテーションやスラッシュを含めたい場合はエスケープしましょう。

エスケープ表記元の文字説明
\”ダブルクォーテーション
\\\バックスラッシュ
\//スラッシュ
\bバックスペース
\f改ページ
\nキャリジリターン(改行)
\rラインフィード
\tタブ
\uXXXX4桁の16進数で表記されたUnicode文字

参考にした記事

https://www.ipentec.com/document/json-character-escape

MTの年別アーカイブの作成

テンプレートの新規作成で記事リストアーカイブを選択する。

マッピングで年別を選択する。

年別アーカイブと名前を付けました。

下記コードを貼り付ける。

archive_type="Monthly"で月、archive_type="Yearly"で年別表示になる。

<$mt:Date format=”%Y” setvar=”thisyear”$>
<mt:ArchiveList archive_type=”Yearly”>
<$mt:ArchiveTitle trim_to=”4″ setvar=”entryyear”$>
<mt:If name=”thisyear” eq=”$entryyear”>
<h3><a href=”<$mt:ArchiveLink$>”><$mt:ArchiveTitle$></a></h3>
<mt:Entries>
<mt:If name=”__first__”><ul></mt:If>
<li><a href=”<$mt:EntryPermalink$>”><$mt:EntryTitle$></a>(<$mt:EntryDate$>)</p>
<mt:If name=”__last__”></ul></mt:If>
</mt:Entries>
</mt:If>
</mt:ArchiveList>

アーカイブへのリンクを表示するページには、下記コードを貼り付け年と件数が表示されるリンクを作成しました。

<mt:IfArchiveTypeEnabled archive_type=”Yearly”>
<mt:ArchiveList archive_type=”Yearly”>
<mt:ArchiveListHeader>
<nav>
<h3><$mt:ArchiveTypeLabel$>アーカイブ</h3>
<div>
<ol>
</mt:ArchiveListHeader>
<li><a href=”<$mt:ArchiveLink encode_html=”1″$>”><$mt:ArchiveTitle$> (<$mt:ArchiveCount$>)</a></li>
<mt:ArchiveListFooter>
</ol>
</div>
</nav>
</mt:ArchiveListFooter>
</mt:ArchiveList>
</mt:IfArchiveTypeEnabled>