BLK-04Blocks
サービス・ジグザグ(脱カード)
サービス/特徴を3-upのカード羅列にせず、左右交互(ジグザグ)の全幅バンドで縦に積むエディトリアル変種。各行は「ドット方眼の面プレート+大インデックス数字」と「箱で囲まないテキスト」を12カラム上でorder入れ替えして互い違いに配置し、hairline罫線+広い余白でグルーピングする。画像素材ゼロ。アンバー罫線とMontserratの巨大アウトライン数字で標本的な編集感を出す(他社サイトに見られる互い違いブロック構図を参考にブランド再構築・2026-07-27)。
- 追加日:
- 2026-07-27
- 依存:
- なし
- tags
- #service #features #block #editorial #zigzag #cardless #hairline #no-image
プレビュー
BLK-04 — Services
私たちにできること
サービスをカードで並べず、ひとつずつを「面」で見せる。 設計から運用まで、成果に必要な工程を左右交互のリズムで。
- S-01 / CORPORATE
- S-02 / LANDING
- S-03 / OPERATION
"use client";
import { useEffect, useState } from "react";
import { Montserrat } from "next/font/google";
const montserrat = Montserrat({
weight: ["600", "700", "800"],
subsets: ["latin"],
display: "swap",
});
/**
* サービス・特徴(脱カードのエディトリアル変種)
* 参考: 他社サイトに見られる「互い違いブロック」構図をブランド再構築(コピーではない)。
*
* 汎用技法メモ(web-design-playbook 還流用):
* - 脱カード=サービスを 3-up のカード羅列にせず、左右交互(zigzag)の全幅バンドで縦に積む。
* 各バンドは sm:grid-cols-12 上で「面(ドット方眼の余白プレート)」と「テキスト」を組み、
* 偶数行/奇数行で order を入れ替えるだけで互い違いのリズムが出る(画像素材ゼロで成立)。
* - グルーピングは箱の border ではなく hairline 罫線(border-t/border-b border-gray-200)+
* 広い縦余白(py)で行う。囲まないことで"面のエディトリアル"に見える。
* - リビールは mount 後 rAF で inView を立て、行ごとに transition-delay をずらすだけ。
* transform/opacity のみ・motion-reduce: で即時表示にフォールバック。
*/
const services = [
{
idx: "01",
code: "S-01 / CORPORATE",
title: "コーポレートサイト制作",
body: "会社の「標準」になるサイトを、情報設計からデザイン・実装まで一貫して。伝わる構造と、育てられる土台を同時に。",
points: ["情報設計", "デザイン", "実装"],
},
{
idx: "02",
code: "S-02 / LANDING",
title: "ランディングページ / LP",
body: "成果から逆算した構成とコピーで、見た人を次の一歩へ。速度・可読性・導線まで、数字で語れる面をつくります。",
points: ["構成設計", "コピー", "計測導線"],
},
{
idx: "03",
code: "S-03 / OPERATION",
title: "保守・改善運用",
body: "つくって終わりにしない。公開後もデータを見ながら、更新・改善・AI活用で軽く回り続ける運用へ。",
points: ["保守", "改善提案", "AI活用"],
},
];
export default function ServiceZigzag() {
const [inView, setInView] = useState(false);
// マウント後にリビール開始(reduced-motion 時は motion-reduce: クラスで即時表示)
useEffect(() => {
const id = requestAnimationFrame(() => setInView(true));
return () => cancelAnimationFrame(id);
}, []);
// リビール用クラス(遅延は各要素の inline transitionDelay で行ごとにずらす)
const reveal =
`transition-[opacity,transform] duration-700 ease-out motion-reduce:transition-none ${
inView
? "translate-y-0 opacity-100"
: "translate-y-6 opacity-0 motion-reduce:translate-y-0 motion-reduce:opacity-100"
}`;
// 面プレートのドット方眼(標本モチーフ・装飾なので aria-hidden)
const dotGrid = {
backgroundImage:
"radial-gradient(circle, rgba(34,30,25,0.10) 1px, transparent 1px)",
backgroundSize: "14px 14px",
};
return (
<section
aria-labelledby="svc-zigzag-heading"
className="w-full max-w-5xl bg-white px-1"
>
{/* ヘッダー */}
<header className="max-w-2xl">
<p
className={`${montserrat.className} text-xs font-bold tracking-[0.25em] text-amber-600 uppercase ${reveal}`}
style={{ transitionDelay: "0ms" }}
>
BLK-04 — Services
</p>
<h2
id="svc-zigzag-heading"
className={`mt-4 text-[clamp(1.8rem,4vw,2.6rem)] leading-[1.25] font-bold tracking-tight text-gray-900 ${reveal}`}
style={{ transitionDelay: "80ms" }}
>
私たちに
<span className="relative whitespace-nowrap">
できること
<span
aria-hidden="true"
className="absolute -bottom-1 left-0 h-[3px] w-full bg-amber-500/70"
/>
</span>
</h2>
<p
className={`mt-5 text-[15px] leading-[1.9] font-medium text-gray-600 ${reveal}`}
style={{ transitionDelay: "160ms" }}
>
サービスをカードで並べず、ひとつずつを「面」で見せる。
設計から運用まで、成果に必要な工程を左右交互のリズムで。
</p>
</header>
{/* ジグザグ・リスト(hairline罫線+余白でグルーピング) */}
<ol className="mt-12 border-t border-gray-200 sm:mt-16">
{services.map((s, i) => {
const visualLeft = i % 2 === 0;
return (
<li
key={s.idx}
className={`grid grid-cols-1 gap-6 border-b border-gray-200 py-10 sm:grid-cols-12 sm:items-center sm:gap-10 sm:py-16 ${reveal}`}
style={{ transitionDelay: `${240 + i * 120}ms` }}
>
{/* 面プレート(画像枠の代わり・ドット方眼+大インデックス数字) */}
<div
className={`relative overflow-hidden rounded-xl bg-[#faf7f2] sm:col-span-5 ${
visualLeft ? "sm:order-1" : "sm:order-2"
}`}
>
<div
aria-hidden="true"
className="absolute inset-0"
style={dotGrid}
/>
{/* 上辺のアンバー罫線 */}
<span
aria-hidden="true"
className="absolute top-0 left-0 h-[3px] w-16 bg-amber-500"
/>
<div className="relative flex aspect-[16/9] flex-col justify-between p-5 sm:aspect-[4/3] sm:p-6">
<span
className={`${montserrat.className} text-[11px] font-semibold tracking-[0.22em] text-amber-700 uppercase`}
>
{s.code}
</span>
<span
className={`${montserrat.className} self-end text-[clamp(3.5rem,9vw,6rem)] leading-none font-extrabold`}
style={{
WebkitTextStroke: "1.5px rgba(34,30,25,0.22)",
color: "transparent",
}}
aria-hidden="true"
>
{s.idx}
</span>
</div>
</div>
{/* テキスト(箱で囲まない=脱カード) */}
<div
className={`sm:col-span-7 ${
visualLeft ? "sm:order-2" : "sm:order-1"
}`}
>
<div className="flex items-baseline gap-3">
<span
className={`${montserrat.className} text-sm font-bold text-amber-600`}
>
{s.idx}
</span>
<span
aria-hidden="true"
className="h-px flex-1 bg-gray-200"
/>
</div>
<h3 className="mt-3 text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
{s.title}
</h3>
<p className="mt-3 max-w-xl text-[15px] leading-[1.9] text-gray-600">
{s.body}
</p>
<ul className="mt-5 flex flex-wrap gap-x-5 gap-y-2">
{s.points.map((p) => (
<li
key={p}
className="border-l border-amber-400 pl-2 text-[13px] font-semibold tracking-wide text-gray-700"
>
{p}
</li>
))}
</ul>
<div className="mt-6">
<a
href="#"
className="group inline-flex items-center gap-2 text-sm font-semibold text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-amber-600"
>
<span className="relative">
詳しく見る
<span className="absolute -bottom-1 left-0 h-px w-full origin-left scale-x-100 bg-gray-900 transition-transform duration-300 ease-out group-hover:scale-x-0 motion-reduce:transition-none" />
<span className="absolute -bottom-1 left-0 h-px w-full origin-right scale-x-0 bg-amber-600 transition-transform delay-150 duration-300 ease-out group-hover:origin-left group-hover:scale-x-100 motion-reduce:transition-none" />
</span>
<span
aria-hidden="true"
className="inline-block transition-transform duration-300 ease-out group-hover:translate-x-1 motion-reduce:transition-none"
>
→
</span>
</a>
</div>
</div>
</li>
);
})}
</ol>
</section>
);
}
shadcn CLI でプロジェクトに追加
npx shadcn@latest add https://designs.first-ch.com/r/service-zigzag.json