スタイリング・フロントエンド豆知識集
主にはNext.js 14・Typescript・TailwindCSS・Storybook環境下で作業する時に、ちょっとした調べ物をしたり、軽くつまづいたことなどをメモしていきます。
需要がありそうなものなどは、そのうち別途記事に切り出します。
svgにimg要素のalt的機能を持たせる
要約:svgにimg要素のalt的機能を持たせたい時は、
<svg role='img' aria-label='説明'></svg>
Safariだと100vhがうまく効かないとき:dvh(dynamic viewport height)を使う
.h-dvh
クラスがある(Safariで問題なく動作することを確認済み・現時点では他ブラウザ未確認🙏)
useState
を使わずにModalの開閉を管理する方法(searchParams
を使う)
useState
を使用するコンポーネントは'use client'
が必要になるが、そうしたくない場合に使えるテクニック
なお、headerなどには使えない(かもしれない)
Tailwind CSSの本が出る!🙌
.sr-only
というクラスの存在を知った…
表示はされないがスクリーンリーダーには認識される
Tail-animistaを使う
Tailwind CSSでアニメーションを楽につけるには:
SNSシェアボタン・リンクコピーの実装
Twitter(X)において、ハッシュタグを複数書きたい時は
hashtags=alpha,beta
のようにカンマで区切って書く
Twitter(X)のシェアURLについて、最新はshare?
ではなくintent/tweet?
となる
またLINEについて、こちらの情報によると
公式ドキュメントには記載されていないが、ブラウザからであれば、share?text=
でテキストも共有できるとのこと
Q「LINEで送る」ボタンでURLと一緒にテキストもシェアできますか?
カスタムアイコンを使って「LINEで送る」ボタンを作成する場合、URLと一緒に任意のテキストをシェアするよう設定できます。詳しくは、「カスタムアイコンを使用」を参照してください。LINE公式アイコンを使用する場合は、URLと一緒にテキストをシェアすることはできません。
FAQの作り方(未精査)
さっとみた限り、FAQ.jsでは<dl><dt><dd>を使ってQとAを書き分けるとよいのではないだろうか?
モバイルファーストでバナーを作成するときの適切な解像度の考え方
デザイン・ワイヤーだと実寸で作っているが、解像度を考えると幅・高さともに倍(=面積は4倍)くらいで書き出した方が良さそう
背景画像などと違い、画面に表示されるサイズが固定となるバナーの作成依頼をするために調べた
Next.js 13以降のImageの設定方法
TailwindCSSと組み合わせる場合、style部分はclassNameに置き換えてよいので、以下のように書くことができる。
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
width={1980}
height={1150}
sizes="100vw"
className={'w-full h-auto'} // styleを書き換え
/>
(layout="responsive"(サイズを可変にする画像)の場合から引用、className部分のみ書き換え)
画面幅に応じて表示文字数を調整したい時は、TailwindCSSのline-clampを使うと楽
Next.jsのサーバーコンポーネント上で、window.innerWidthなどを使用して画面サイズを取ろうとすると、windowオブジェクトはクライアントサイドでしか動作しないため、エラーとなってしまう。
しかし、文字列が長いときに折り返されるのを避けたいだけであれば、
TailwindCSSのline-clampを使用することで、動的な処理を一切書くことなく解決できる。
<p className='line-clamp-1'>Lorem ipsum dolor sit amet,</p>
と書くだけで、画面要素の幅より長い文字列は、その要素幅にあった長さに丸められ、末尾に「...」が付与される。
もちろん、line-clamp-3
と書けば3行の範囲内で丸められ、ブログ記事の冒頭をチラ見せするのに使用するなど、複数行表示するのに使う方が多いかもしれない。
縦方向に数行要素を並べた上で、更に横スクロールする時のTailwindCSSのクラス
<ul className='flex flex-col overflow-x-auto flex-wrap max-w-430px h-[390px]'>
{items.map((item: any, index: number) => (
<li key={index} className={index < 5 ? 'mx-5' : 'mr-5'}>
<div className={w-[calc(100vw_-_40px)] max-w-[370px] h-[70px]}>省略</div>
<div
className={`w-[calc(100vw_-_40px)] max-w-[370px] h-1px bg-gray-300 mb-[9px] ${
index % 5 === 4 || index === items.length - 1 ? 'hidden' : ''
}`}
/>
</li>
))}
</ul>
ポイント
-
<ul>
内のTailwindCSSクラス-
flex-col
で縦方向に並べる -
overflow-x-auto
で横方向にスクロール -
flex-wrap h-[390px]
で、390pxを超えたら折り返して並べるようにしている(390px
はliを5つ並べた時の高さが80px * 4 + 70px = 390px
のため) -
max-w-430px
で表示幅をトリミング
-
-
<li>
内のTailwindCSSクラス-
items.length
を活用し、状況に応じたクラスの使い分け- コード3行目:最初の5つの
<li>
だけは左右にマージンをつけたい、それ以外は右側にだけつけたい - 7行目:縦に
<li>
を5行ならべた際の5つ目と最後の<li>にはこの要素を表示させない
- コード3行目:最初の5つの
-
古のMarqueeタグ
はHTML5で非推奨となった 【解決法①】 【解決法②】
TailwindCSS単体で作成できないグラデーションの実装・テキストグラデーション
こちらに記事を作成しました
Next.js 14でのfavicon設定方法
public
に配置して自力で<head/>
に記述するものが多いが、上記リンク先で書かれている通り、favicon
とapple-touch-icon
は/app
の中に置けばよい
しかしandroid-chrome
については記載がない
android-chrome
に関する仮説】
【- Next.jsでプロジェクトを作成したときに入っているデフォルトの
favicon.ico
には256 * 256も含まれていたので、favicon.ico
がchrome-android
もカバーしている? -
icon.png
として256 * 256のicon
を作成すればそれが適用される?
仮説を元に必要なファイル・画像サイズを洗い出す
種類 | ファイル名 | サイズ |
---|---|---|
favicon | favicon.ico | 16x16, 32x32, 256x256 |
apple-touch-icon | apple-icon.png | 180x180 |
chrome-android | icon.png | 256x256 |
検証結果
AndroidのChromeでページのタブアイコン、お気に入り登録した際のアイコン、ホーム画面に追加した際のアイコンを確認した結果、
- タブ ...
favicon.ico
が出たりicon.png
が出たりと結果がまちまち(同サイズだからか?) - お気に入り ...
icon.png
が表示される - ホーム画面 ... アイコン表示されず(URLの一文字目+Chromeアイコンに)
と必ずしもicon.png
が表示されるとは限らない結果に。
ただ、他サイトをホーム画面に追加してもアイコンが表示されるケースが確認できなかったため、ホーム画面に関しては別のところに原因がある可能性も。
またChromeで新規タブを開いた際に表示される、クイックアクセスにはicon.png
が表示されることを確認した。
Next.js 14で動的にOGP画像を生成する際のつまづきポイント
基本はこれに沿って行う
export const runtime = 'edge'
runtime
のデフォルトはnextjs
なので要注意
つまづきポイント0:プレビューしたい…!
でできる!
<img>
か<div>
で読み込む
つまづきポイント1:画像はいつもの習慣でimport Image from 'next/image'
しようとしてしまったが、
(正確にはfunction Image()
とぶつかるため、import NextImage from 'next/image'
)
Error: failed to pipe response
Cannot access Image.toString on the server. You cannot dot into a client module from a server component. You can only pass the imported name through.
というエラーになる
やりたいことは画像を読み込むだけなので、今回は<img>
タグで回避
<div>
のdisplayはflex
かnone
しか選べない
つまづきポイント1.5:些細なことではあるが、意外とこれに触れている記事は少ない
flex
かnone
しか選べない時点で、必然的に<div style={{display: 'flex'}}>
となる
詳細はこちら
つまづきポイント2:日本語フォントの読み込み
こちらを参照して解決
つまづきポイント3:TailwindCSSで書ける、ただしtailwind.config.tsは効かないし、いくつか効かないクラスがある
truncate
、line-clamp-1
、object-contain
あたりが効かず、styleにcssで記載した
しかし、textOverflow: 'ellipsis'
は適切に効かず、...
が途切れてしまうことがあった
※また<h1>
などにはデフォルトで上下にmargin
が入っているので、m-0
などが必要
つまづきポイント4:ドメインの取得
app/middleware.ts
を作成し、ドメインを取得したい箇所(今回はopengraph-image.tsx
)に下記の要領で記載
(※上記例ではlayout.tsx
に記載しているが、layout.tsx
に書かないといけないわけではない)
/* eslint-disable @next/next/no-img-element */
import { ImageResponse } from 'next/og'
import { headers } from 'next/headers'
// (中略)
export default async function Image({ params }: { params: { slug: string } }) {
const header_url = headers().get('x-url') || ''
const url = new URL(header_url)
const hostName = url.host // ドメイン名(ホスト名)を取得
const protocol = url.protocol // プロトコルを取得 ('https:' または 'http:')
return new ImageResponse(
(
<div>
<img
src={`${protocol}//${hostName}/ogp.png`}
alt={''}
/>
</div>
)
)
}
脱線:意外とOGP画像のデザインについてまとめた記事が多くはなかったので、見つけた物を
やってみたい:
回転させたオブジェクトの位置指定(absolute, fixed)
TailwindCSSで書くと
<div className='fixed top-0 right-60px w-[100vh] h-60px -rotate-90 origin-top-right bg-white'>
縦横スクロールのスタイル調整(特に横)
横スクロールがあるデザインを行う時、ブラウザごとの横スクロールバーデザインの違い・OSによる表示/非表示の設定(Mac)によってレイアウトが崩れてしまうことがある
こちらの解決はTailwindCSSでは不可能
::-webkit-scrollbar {
width: 10px;
/* ↓ 横スクロールバー用にheightが必要 */
height: 10px;
background-color: #f7f7f7;
}
::-webkit-scrollbar-thumb {
background-color: #c9c9c9;
/* ↓ あまり理想的な形状にはならないため、思い切って省くのもアリでは */
border-radius: 8px;
}
/* 細かく指定するのは面倒なのでhtmlに直で適用する(bodyだと適用できない)*/
html {
scrollbar-color: #c9c9c9 #f7f7f7;
/* ↓ 横スクロールバーにも適用される様子 */
scrollbar-width: auto;
}
画像の保存防止(Next.js)
これら2つを掛け合わせて、右クリック・ドラッグ&ドロップによる画像保存を行う方法として、以下を採用した
/* 画像保存防止 */
img {
/* PCの右クリック禁止 */
pointer-events: none;
/* SPの長押し禁止 */
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-touch-callout: none;
-moz-user-select: none;
user-select: none;
}
なお、layout.tsx
の<body />
やnext/image
のImage
にoncontextmenu
、onselectstart
、onmousedown
の処理を書こうとしたが、エラーとなってしまった(client componentではないことによるものと、next/imageの仕様によるもの)ため、画像とその外側のdivを別途client componentとして書き出し、そちらに以下のように記載した
<div
onContextMenu={(e) => e.preventDefault()}
onSelect={(e) => e.preventDefault()}
onMouseDown={(e) => e.preventDefault()}
>
<Image />
</div>
Next.jsでスクロールポジションを保ちつつ画面遷移する方法
リンク遷移後のスクロールポジションを保ちたい時には、
< Link scroll={true} />
これだけでOK!!!
<ol>
の数字を(1)など自在にカスタマイズするには
規約とか書くのに役立った ... beforeに『第1章』など付けられる
CSSのcounter-incrementを使って簡単に自動で連番をつける方法
よさげなIdenticon3選
マイページなどにユーザーアイコンを設定したい、しかしユーザ情報はユーザ本人にしか表示されないので、ユーザが任意に画像を設定できる仕組みまで作るのはオーバーヘッド→Identiconライブラリを使おう!
【GitHub風Identicon】minidenticons
npm install minidenticons
【幾何学だけどかわいい】JDENTICON
npm install jdenticon
【ゆる顔アイコン・マーブル模様など6パターン】
npm install boring-avatars
こちらで試せる
minidenticonsとboring-avatarsを試したが、boring-avatarsの方が色味を設定できたり、useMemoが必要ないため、server componentでも使用できるなど、使い勝手は良い
ただ、6種類の見た目があるが、実際にアイコンとして特徴的な見た目が生成されるのは、beamとbauhausの2種類と感じた