ニュースの一覧ページやブログカード、商品一覧などでは、各詳細ページへのリンクをサムネイルと内容の文頭のみでカード形式で作成することが多いと思います。その際文頭を省略記号「…」で切り取る実装が求められることがあります。今回はJavaScriptとCSSを使ってこの実装方法について解説します。
JavaScriptでの設定方法
JavaScriptで設定する際は、表示する文字数を指定し、指定した文字数以上は「…」を表示するという処理を行います。
sliceを使った例
slice
メソッドは、文字列の一部を抽出するために使用します。最初の引数には抽出を開始する位置(0から始まるインデックス)、2つ目の引数には終了する位置(その文字は含まれません)を指定します。
例えば、次の例では文字列の0文字目から30文字目までを抽出し、続けて「…」を追加しています。
const paragraph = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';
// 文字列を29文字目まで抽出し、省略記号「...」を付ける
<p>{paragraph.slice(0, 30)}...</p> // 出力: Lorem ipsum dolor sit amet, co...
簡単に実装するのであればこの方法でも良いのですが、このコードではparagraphが30文字未満の場合でも文末に「…」が表示されてしまいます。この問題を解決するには、文字数を条件に応じて判定する関数を作成する必要があります。下記で例を紹介します。
カスタムフックを使った例(React.js, Next.js)
React.jsやNext.jsでは、頻繁に再利用する機能をカスタムフックとして作成しておくと便利です。使用したいページにカスタムフックのファイルを読み込んで、好きな箇所で関数を呼び出すことができるので、コードの重複を避け綺麗なコードを保つことができます。
// 同じ入力に対して不要な再計算を避ける
import { useMemo } from "react";
// paragraph: 表示する文字列
// textNum: 表示する文字数
export const useTextCount = (paragraph: string, textNum: number) => {
// paragraphがtextNumを超えている場合は指定文字数+「…」返す
const truncatedText = useMemo(() => {
return paragraph.length > textNum
? paragraph.slice(0, textNum) + "…" // 例: "Lorem ipsum dol..."
: paragraph; // paragraphがtextNum以下の場合は元の文字列をそのまま返す
}, [paragraph, textNum]);
return truncatedText;
};
文字数制限をしたい箇所に適用。
// 一つ目の引数に表示したい文字列、二つ目に表示させたい文字数を指定
<p>{useTextCount(item.content, 100)}</p>
全体のコード(使用例)。今回はTailwindCSSを使用しました。TainwindCSSは簡単にスタイルを指定できるので、UI作成にとても便利です。
import newsData from "./constant/news.json";
import { useTextCount } from "./hooks/useTextCount";
function App() {
return (
<main className="flex flex-col items-center gap-8 py-16 max-w-[1280px] mx-auto">
<h1 className="text-4xl font-bold">News</h1>
<div className="w-full grid grid-cols-3 gap-6">
{newsData.news.map((item) => (
<a
href={`news/${item.id}`}
className="rounded-lg shadow-md border border-stale-600 bg-stale-50"
>
<div className="w-full">
<img
src={item.img}
width="500"
height="300"
className="rounded-t-lg max-h-[300px]"
/>
</div>
<div className="p-3 flex flex-col gap-2">
<div>
<span className="text-sm text-gray-400">{item.date}</span>
<h2 className="font-bold">{item.title}</h2>
</div>
<p>{useTextCount(item.content, 30)}</p>
<span className="text-sm text-right">Read more</span>
</div>
</a>
))}
</div>
</main>
);
}
export default App;
手軽に文字数を制御したい場合はSlice
を使用し、複雑な要件やReact.js, Next.js環境での再利用を考えているのであればカスタムフックを使用するなどで使い分けるといいかと思います。
CSSでの設定方法
CSSで設定する際は、省略したい文章を囲んでいるタグに下記スタイルを付与するだけで、コンテンツの幅に合わせて自動で「…」が表示されます。レスポンシブ対応で画面幅によってコンテンツの幅が変化しても、変化したコンテンツ幅に合わせてちゃんと対応してくれるので見た目も綺麗です。
TailwindCSSを使った例
TailwindCSSではtruncate
を使用するだけでOKです。ただし、このクラスは1行分しか文章が表示されないので、複数行表示したい場合は下記CSSでの方法が必要です。
<p class="trunscate">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
ちなみにCSSの中身はこのようになっています。
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
CSSを使った例
CSSでは表示する行数の指定も可能です。「…」の表示に加え、-webkit-line-clamp
にて行数を指定することで、好みの行数 + 省略文字「…」を表示させることができます。なお、-webkit-line-clamp
はモダンなブラウザ(Chrome、Edge、Safariなど)でサポートされていますが、IEでは動作しないため、対象ブラウザを確認してください。
<p class="truncate-multiple">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat</p>
.truncate-multiple {
display: -webkit-box;
-webkit-line-clamp: 3; /* 表示したい行数を指定 */
-webkit-box-orient: vertical;
overflow: hidden;
}
まとめ
JavaScriptとCSSでの省略記号「…」の表示方法について紹介しました。
仕様やデザインで表示する文字数が決まっている場合や複数箇所で使用予定がある場合は文字数制限ができるJavaScript、カスタムフックを使用し、コンテンツの幅に合わせて綺麗に見せたい、レスポンシブ対応が必要な場合はCSSを使用するなど状況によって使い分けてみてください。