Youtubeショート動画を埋め込みレスポンシブ対応する

2024/10/12 (土) - 10:00 CSSHTML

Youtubeのショート動画が増えてきましたね。TiktokやLINEのVOOM、Instagramのタイムライン動画など、流しながら次々と見られる動画がプロモーションやサービス訴求としても非常に有効です。ショート動画をWebページに埋め込みたいけど、普通の動画と違って共有ボタンに[埋め込みコード]を出力する手段がありません。ショート動画を埋め込みたい時はどうすればいいでしょうか?

HTMLとCSSの実装

埋め込みコードをコピー

埋込したいショート動画にアクセスし、動画の上で右クリックし[埋め込みコードをコピー]を選択します。次に埋め込みたいWebページの任意の位置に以下のようにコードを埋め込みます。

<div class="youtube_short"><iframe width="315" height="560" src="https://www.youtube.com/embed/動画ID" title="動画タイトル" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

CSSを設定する

レスポンシブ対応のため以下のようにCSSを実装します。スマホでは画面からはみ出ないよう、またPCでは横幅が大きくなりすぎて高さがはみ出ないような数値にします。

.youtube_short{
 width: 70%; /* 伸縮する横幅 */
 max-width: 400px; /* 最大の横幅 */
 margin: auto; /* 画面の中央に配置 */
}
.youtube_short iframe{
 aspect-ratio: 9 / 16;
 width: 100%;
 height: 100%;
}

しかのこのこのここしたんたん

表示例

Next.jsのApp Routerでサーバーサイドでクエリパラメータと動的パスを取得する

2024/10/07 (月) - 10:00 JavaScript

前回はクライアントコンポーネントで動的パスやクエリパラメーターを取得しましたが、今回はサーバーサイド(サーバーコンポーネント)で取得する場合の方法。下記のコードでサーバーサイド(SSR)で動作するようです。例として/[slug]/page.jsという動的ルーティングのファイルを作成して、/taro/?id=10にアクセスした場合。

export default function Page(props) {
 const slug = props.params.slug;
 const pram = props.searchParams.id;
 return (
  <main>
   <p>パスは、<i>{slug}</i>です。</p>
   <p>GETパラメータは、<i>{pram}</i>です。</p>
  </main>
 );
}

paramsで動的パス、searchParamsでクエリパラメータを取得できました。

応用編。気象庁のAPIを取得表示するサンプル。http://localhost:3000/130000/にアクセスしたら東京都の気象情報を表示する…的な。

const getData = (slug) => fetch(`https://www.jma.go.jp/bosai/forecast/data/overview_forecast/${slug}.json`).then((res) => { return res.json()});
export default async function Page(props) {
 const slug = props.params.slug;
 const data = await getData(slug);
 return (
  <main>
   <p>{data.targetArea}の天気は{data.targetArea}です</p>
  </main>
 );
}

CSSとReactで制御する簡易ハンバーガーメニュー

2024/10/04 (金) - 10:00 CSSJavaScript

Reactでハンバーガーメニューを実装するとき、動きや見た目を完全分離させて実装したいと思った。その場合は一番上のDOM階層のhtml要素にclass属性を付与して、ボタンの表示非表示やボタンの形状などを変更するのがロジック的には最もシンプルだろう。メリットとしては…

  • html要素にclassを付与することで全体のスタイル実装が容易になる
  • style属性による表示の制御は、レスポンシブの観点からバッドノウハウである
  • ハンバーガーメニュー表示中は全体スクロールを抑制したい
  • ロジック・見た目とギミックは分離したい

ReactのuseStateでハンバーガーメニューのボタンのオンオフを制御だけして、html要素へは単純にtoggleClassするだけにした。もっといい方法があるかもしれないが、今回のアプリケーションはこれが最適だったが、別にここはReactでなくてもいいじゃんね…とは思ったけど。

JavaScript部分

〜略〜
 const [isMenu, setisMenu] = useState(false);
 const onClickToggle = () => {
  setisMenu(!isMenu);
  //htmlタグにclass属性をtoggleする
  if(isMenu){
   document.documentElement.classList.remove('menuActive');
  }else{
   document.documentElement.classList.add('menuActive');
  }
 }
 return (
  <div>
   <button onClick={onClickToggle} className="btn_menu">[ハンバーガーメニューボタン]</button>
  </div>
 );
〜略〜

CSS部分

.menuActive{
 /*メニューが出現したらページ全体のスクロール制御*/
 overflow: hidden;
}
.nav_menu{
 /*メニュー部分 詳細は中略*/
 /*メニューが出現するアニメーション制御*/
 transform: translateX(-100%);
 transition: .25s transform;
}
.menuActive .nav_menu{
 /*アニメーションでメニューが出現*/
 transform: translateX(0%);
}
.btn_menu{
 /*ハンバーガーメニュー部分 詳細は中略*/
}
.menuActive .btn_menu{
 /*ハンバーガーメニュー押下した状態 ボタンの形状を「×」に切り替えるなど*/
}

Chromeで色覚異常の見え方をシミュレーションする

2024/10/02 (水) - 10:00 Design

色覚異常とは正常な色覚の人と異なり、特定の色の認知度が低下している体質のことです。例えば色覚異常の傾向がある人は赤い色が見えにくかったり、緑や青が見えなかったりなど様々な症状が出ることがあります。

バーベキューの正常な見え方と色覚異常の見え方(※1型2色覚)生肉と焼けた肉の際が分かりづらい

上のバーベキューの写真だと、正常な見え方だと焼けた肉と生肉の違いに気が付きますが、色覚異常があるとパッと見で差がわかりにくかったりします。その他にも色が見えない異常(モノクロになる)や色のコントラストが飛んでしまう異常など症状は様々です。

Webサイトや印刷物、ポスター等を制作する過程において、多くの人が見てわかりやすくなるよう色にも気を遣ってデザインしなくてはなりません。

Chromeで色覚異常の見え方チェックを行う

実はGoogle Chromeでは色覚異常の見え方を確認できます。まず対象のWebサイトを開き、Web開発者ツールを起動します。縦の三点メニューから[その他のツール]から[レンダリング]を選択します、

Web開発者ツールによる色覚異常エミュレータ

スクロールすると表示されれる[色覚異常をエミュレート]のプルダウンから様々な見え方をシミュレーションできます。

デフォルトの見え方(一般色覚)(C型)

デフォルトの見え方

かすみ目

かすみ目の見え方

低コントラスト

低コントラストの見え方

1型2色覚(赤色の識別不可)(P型)

1型2色覚(赤色の識別不可)の見え方

2型2色覚(緑色の識別不可)(D型)

2型2色覚(緑色の識別不可)の見え方

3型2色覚(青色の識別不可)(T型)

3型2色覚(青色の識別不可)の見え方

色覚異常(色の識別不可)

色覚異常(色の識別不可)の見え方

デザイン段階でチェックしよう

Webサイトを制作し終わってからデザインのアクセシビリティチェックを行うと、デザインまで巻き戻りかえって工数が増えてしまうことがあります。要件定義とデザインの段階でどこまでガイドラインを重視するのかはあらかじめ決めておきましょう。ユニバーサルデザイン(多目的・多様性デザイン)を促進するようなWebサイトでは以下の点に配慮しましょう。

  • 色に囚われないデザインをする(色によって機能や目的を分けるのは控える)
  • 色以外でデザインする(形やピクトグラム、アイコンで補助する)
  • 背景色・文字色のコントラスト差を確保する(読みやすい色差を意識する)

戻るボタンで広告が表示されるギミックを簡易的に実装する

2024/09/27 (金) - 10:00 JavaScript

最近ニュースサイトやブログなどで、ブラウザの戻るボタンを押したら広告やレコメンド記事が表示される謎演出がありますよね。今日はあれを簡易的に再現してみます。

Chrome、Firefox、Safariで動作チェック済みです。上記のページの[続きを読む]のボタンを押下したあと、ブラウザバックをするとダミーの広告が出るはずです。以下のコードを設定しました。非常に簡易的なものです。今後のWebブラウザのアップデートで正常に動かなくなる可能性はありますが…。

//何かしらアクションを起こしたときに履歴を操作
window.history.pushState(null, null, window.location.href);

window.addEventListener('popstate', (e) => {
 //戻るボタンを押したときにアクションをおこす
});

まずhistoryAPIのhistory.pushStateを使い、任意に履歴を追加します。そのあとpopstateのイベントハンドラで戻るボタンが押されたタイミングで特定のイベントを発火させます。この時、広告を出す系のサイトでは広告やレコメンド記事エリアを表示させるような処理をしているはずです。

しかし、これはユーザの本来の意図とは反する動きなのでUX(User eXperience)的には好ましいことではありません。ですが、戻るボタンの検知自体は場面次第では有効なことがあります。例えば…

  • Webアプリ等で戻るボタンの動作を抑制・警告させたい
  • フォームや申し込み、購入画面などで誤動作・二重処理を防止したい
  • 広告ではないポップアップ表示を戻るボタンで消すようにしたい

…等。ユーザのことを考えて、使う場面を見極めましょう。

Photoshopの画像アセット生成で拡大で書き出すとぼやける

2024/09/20 (金) - 10:00 Design

Adobe Photoshopで、画像のレイヤーからJPEGやPNGといった画像を書き出すことのできる画像アセット生成機能。レイヤー名にファイル名をつけて[ファイル]→[生成]→[画像アセット]をオンにすると、PSDファイルのあるフォルダに設定した画像ファイルを生成できます。詳しくは下記にて。

Webページのデザインカンプからコーディング用に画像を生成したいときは非常に便利です。この機能の便利なところは、書き出す画像ファイルの大きさを任意に変えることができることです。Retina用に画像を高画質に生成したい場合などに使えます。

Adobe Photoshopのレイヤー

例えばレイヤー名に[200% image.png]と設定し生成するとPSDで配置している画像サイズの2倍の大きさで書き出せます。大きな画像を用意してPSDに配置し、[スマートオブジェクト]に変換して縮小・配置することで画質を気にせず生成できます。

拡大して生成すると画像がボヤける

高画質画像のソースを読み込みスマートオブジェクトにして配置し、画像を倍の大きさにして生成してみたのですが、なぜか画像がぼやけてしまうという事象が発生。Adobe Photoshop 2024で発生を確認しました。色々検証すると以下の場合に発生することが判明。

  • 画像を[埋め込みを配置…]、或いは[リンクを配置…]で読み込みスマートオブジェクトで配置
  • 画像ソースがJPEG形式、或いはPNG形式、TIFF形式など
  • 200%など拡大して生成している

原因は画像ソースがJPEG形式やPNG形式であることでした。試しに画像ソースをPSD形式にしたらきれいに生成できました。

画像ソースがJPEGの場合。猫の写真や文字がボケていると思います。

画像がぼける

画像ソースがPSDの場合。きれいでくっきりしていると思います。

画像がきれい

もし、PSDのドキュメント上に埋め込みやリンクで画像を配置する場合は、多少ファイルが大きくなってしまいますがPSD形式で作って運用したほうが良さそうです。

EC-CUBE4で会員情報と注文(受注)情報をリセットする

2024/09/17 (火) - 00:00 PHP&CMS

EC-CUBE4で会員情報と注文情報を全部削除する方法。開発中の環境でテスト情報を削除したい場合などに使います。環境はEC-CUBE 4.2.xで、MySQL 5.7で検証を行っております。バージョンが異なったりするとテーブルが変わってる可能性もあるのでご注意ください。

念の為、データベースの内容をdumpするなどバックアップを取ってから行いましょう。まずMySQLにログインし、対象のデータベースにアクセスします。

注文情報の削除

TRUNCATE TABLE dtb_order_item;
TRUNCATE TABLE dtb_mail_history;
TRUNCATE TABLE dtb_shipping;
TRUNCATE TABLE dtb_order;
ALTER TABLE dtb_order AUTO_INCREMENT = 1;

注文商品、受注メールの履歴、注文の配送先情報、注文情報を空にします。AUTO_INCREMENT = 1;で、行のIDを1から割り振り直します。

会員情報の削除

TRUNCATE TABLE dtb_customer;
TRUNCATE TABLE dtb_customer_address;
TRUNCATE TABLE dtb_customer_favorite_product;
ALTER TABLE dtb_customer AUTO_INCREMENT = 1;

会員情報、配送先、お気に入りに登録を空にします。

もし、外部テーブル制約でエラーが出た場合は、SET FOREIGN_KEY_CHECKS = 1;で外部テーブル制約を一時的に無効にしましょう。終わったらSET FOREIGN_KEY_CHECKS = 0;で元に戻します。

EC-CUBE管理画面

EC-CUBEの管理画面からデータが消えていることを確認します。

[さくらのレンタルサーバー]メールフォームから自分自身のドメイン宛にメールが届かない(メールが送信できない)

2024/09/12 (木) - 10:00 Server

自社のWebサイトのメールフォームから他のドメインのメールアドレスにはメールは送れるのに、自分のドメイン宛(管理者メールなど)にメールが送れない時があります。これは以下のような場合に発生することがあります。

さくらのレンタルサーバ メールドメイン設定

  • メールサービスを自身のさくらのメールボックスでは無く、外部のソリューションを使っている(Google WorkspaceやSendGrid等)
  • Webサーバとメールサーバが一緒になったサービスを使っている
  • 独自ドメインかつ、メールフォームとメール送信先が同じドメインである

WordPressのメールフォームプラグインであるMW WF Formでも同様に、「エラーが発生しました。後ほどもう一度お試しください。」というエラーメッセージだけが表示され原因が特定しづらいことがあります。

これらはメールの配送がローカル配信(内部配送、内部回送)していることが原因です。この場合、Webサイトのメールフォームから送ろうとしたメールはインターネットを介しドメインのMXレコードで指定しているサーバに送信するのではなく、インターネットから出ずに自身のローカルサーバ内で配送しようとするため発生するものです。以下にヒントがありました。

ローカル配送(内部回送)を停止する

さくらのレンタルサーバーのコントロールパネルにアクセスし、[メール]→[メールドメイン]に遷移し、使用しているドメイン名の[設定]から[メールドメイン設定]をクリックします。

さくらのレンタルサーバ メールドメイン設定

メールの利用範囲から、[選択したドメインはメールでは利用しない]を選択して保存します。これによりメールを送信する時MXレコードで指定されたサーバーに送信されます。

関連リンク

テキストボックスに入力した文字でHTMLリストを絞り込み表示する

2024/08/11 (日) - 10:00 JavaScript

テキストボックスで入力した文字が含まれるリスト要素だけを検索して絞り込み表示させてみたい。まず検索対象となるJSONのdataオブジェクトを用意します。今回はサンプルとして検索対象をカタカナと英文字のみの単語リストとしています。

'data':[
 {
  'id':1,
  'name':'イクイノックス(Equinox)'
 },
 {
  'id':2,
  'name':'リバティアイランド(Liberty Island)'
 },
 {
  'id':3,
  'name':'ジャスティンパレス(Justin Palace)'
 },
 {
  'id':4,
  'name':'タイトルホルダー(Titleholder)'
 },
 {
  'id':5,
  'name':'ドウデュース(Do Deuce)'
 },
 {
  'id':6,
  'name':'エフフォーリア(Efforia)'
 },
 {
  'id':7,
  'name':'パンサラッサ(Panthalassa)'
 },
 {
  'id':8,
  'name':'タスティエーラ(Tastiera)'
 },
 {
  'id':9,
  'name':'スターズオンアース(Stars on Earth)'
 },
 {
  'id':10,
  'name':'ソダシ(Sodashi)'
 },
]

HTMLは検索用のテキストボックスと実際に表示するリスト要素をを用意します。

<!--↓検索ボックス-->
<input type="text" id="txtSearch" placeholder="検索キーワードを入力">
<!--↓一覧表示用リスト要素-->
<ul id="listSearch"></ul>

検索サンプル

以下が検索用のJavaScriptのコードになります。今回のサンプルは検索対象はカタカナなので、検索テキストボックスにひらがなを入力した場合でも、カタカナが検索対象となります。また半角の英文字を入れた場合でも大文字小文字関係なく検索できるようにしています。

const txtSearch = document.getElementById('txtSearch'); //検索用テキストボックス要素
const listSearch = document.getElementById('listSearch'); //一覧のリスト要素
const datas = {JSONデータ}; //JSONデータ
let searchText = '';
let searchResult = datas;
const searchResultList = () => {
 while( listSearch.firstChild ){
  listSearch.removeChild( listSearch.firstChild );
 }
 searchResult.map((search) => {
  listSearch.insertAdjacentHTML('beforeend',`<li>${search.name}</li>`);
 });
}
//↓入力テキストを、英数小文字&ひらがな→カタカナに変換
const changeKata = (str) => {
 str = str.toLocaleLowerCase().replace(/[ぁ-ん]/g, function(s) {
  return String.fromCharCode(s.charCodeAt(0) + 0x60);
 });
 return str;
}
txtSearch.addEventListener('input',function(e){
 searchText = changeKata(e.target.value);
 searchResult = datas.filter((data) => {
  //↓検索対象の文字列を英数小文字に変換
  return data.name.toLocaleLowerCase().includes(searchText);
 })
 searchResultList();
});
searchResultList();

実行結果

検索テキストボックスに「あ」あるいは「ア」と入れると単語に「ア」が含まれる単語のみのリストが表示されます。

検索サンプル ひらがなを入力

検索テキストボックスに「a」あるいは「A」と入れると単語に「a」が含まれる単語のみのリストが表示されます。

検索サンプル 英文字を入力

今回は普通のJavaScriptで簡易的に実装したものになりますが、実装次第ではひらがな・カタカナ混在する単語、全角半角英数が混在する単語を検索する…などもできます。

Next.js[App Router]とPokeAPIでポケモンを番号で検索する。

2024/04/09 (火) - 00:00 JavaScript

前回テストでNext.jsでパスの取得方法を試してみたので、今回はそれとPokeAPIのテストを応用して、ポケモン番号でポケモンを探せるやつを作りました。

検索画面ではポケモンの番号を入れる検索のテキストボックスと検索実行ボタンのみ配置。

キルリア

ポケモン検索ボックスのあるpage.jsのコード。

"use client"
import { useState } from 'react';
import { useRouter } from 'next/navigation'
function PokeAPIHome() {
 const [number,setNumber] = useState(null);
 const router = useRouter();
 const buttonGO = (number) =>{
  router.push(number);
 }
 const onChange = (e) =>{
  setNumber(e.target.value);
 }
 return (
  <div>
   <form>
    <p>ポケモンの番号を入れてね</p>
    <p><input type="number" min="1" value={number} onChange={ onChange } placeholder="151" />
    <button type="button" onClick={ () => buttonGO( number ) }>ゲットだぜ!!</button></p>
   </form>
  </div>
 );
}
export default PokeAPIHome;

表示結果の[number]/page.jsのコード。

検索ボタンを押下すると、/ポケモン番号/というパスで遷移させる想定です。例えば入力画面で151と記入したら/151/というパスに遷移して、ミュウが表示れる…というもの。

import { notFound } from 'next/navigation'
async function PokeAPIDetail({ params }) {
 const number = params.number;
 const pokeAPI = `https://pokeapi.co/api/v2/pokemon/${number}`;
 const getAPI = async(url) => {
  const res = await fetch(url);
  if (res.ok) {
   return res.json();
  }else{
   notFound();
  }
 }
 const getPokemonName = async(data) => {
  const PokemonName = data.names.find((val) => val.language.name === "ja");
  return PokemonName.name;
 }
 const getPokemonType = async(data) => {
  let typeText = '';
  typeText = data.map( async(t,i) => {
   const getTypes = await getAPI(t.type.url);
   const getType = getTypes.names.find((val) => val.language.name === "ja");
   if(i>0){
    return '/'+getType.name;
   }else{
    return getType.name;
   }
  });
  return typeText;
 }
 const dataAPI = await getAPI(pokeAPI);
 const IMG = dataAPI.sprites.other['official-artwork'].front_default;
 const Name = await getAPI(dataAPI.species.url);
 const Type = getPokemonType(dataAPI.types).then(res => {
  return res;
 });
 const NameJA = getPokemonName(Name).then(res => {
  return res;
 });
 return (
  <div>
   <p>No.{number}</p>
   <p><img src={IMG} alt={NameJA} width="250" height="250" /></p>
   <h2>{NameJA}</h2>
   <p>{Type}</p>
  </div>
 );
}
export default PokeAPIDetail;

実行結果。281と検索するとキルリアが表示されました。

キルリア

なお、前のコードを流用して突貫で作成したのでエラー処理はそこまで作り込まず。もしAPIでエラーが発生したら404エラーとして遷移するだけです。

めのまえが まっくらに なった…!

node.jsが動くサーバにデプロイして正常に動くことは確認しましたが、検索周りの処理の作り込みがまだ甘いので改良の余地あり。

ページの先頭へ