フッター
プレビュー
特徴
-
レスポンシブデザイン: スマホ・タブレット・PC などの画面サイズに合わせて要素が自動的に並び替わり、見やすさを確保します。
-
ロゴは任意:
logo
を指定しない場合はロゴ部分が表示されず、ナビアイテムは右寄せ表示になります。 -
アクセシビリティ: リンクに対して
hover
やfocus
などの状態をわかりやすく示すスタイルを適用し、キーボードユーザーにも配慮した設計です。 -
ダークモード対応: 背景色や文字色がシステム設定に合わせて自動的に切り替わり、各デザインシステムのトークンにも対応。
-
最小限の Props:
logo
(省略可)とnavItems
のみでリッチなフッターを簡単に実装できます。
ロゴが長い場合でも、レイアウトが崩れないように適切なスタイリングを行っています。
プロパティ
プロパティ名 | 型 | デフォルト値 | 説明 |
---|---|---|---|
logo | string | 省略可 (空文字や未指定の場合はロゴ非表示) | フッター左側に表示される文字列。指定しない場合は右寄せのリンクのみが表示されます。 |
navItems | {label: string; href: string;}[] | [ { label: "Privacy Policy", href: "/privacy" } ] | フッターに表示したいリンクの配列。 |
Github
コード例
import "@/styles/tailwind.css";
type NavItem = { label: string; href: string;};
type FooterProps = { logo?: string; navItems?: NavItem[];};
export default function Footer({ logo, navItems = [ { label: "About", href: "#" }, { label: "Contact", href: "#" }, { label: "Q&A", href: "#" }, ],}: FooterProps) { return ( <footer className="relative w-full bg-white text-black dark:bg-black dark:text-white mt-8"> <div className="absolute top-0 left-0 w-full h-[2px] bg-gradient-to-r from-lime-500 via-teal-400 to-blue-500" /> <div className={`flex flex-col md:flex-row items-center px-4 py-6 gap-4 text-center md:text-left md:px-8 ${ logo ? "md:justify-between" : "md:justify-end" }`} > {logo && ( <h2 className="text-xl font-bold overflow-hidden text-ellipsis whitespace-nowrap"> {logo} </h2> )} <nav className="flex flex-wrap items-center gap-4 md:gap-8 justify-center md:justify-end w-full md:w-auto"> {navItems.map(({ label, href }) => ( <a key={href} href={href} className="block px-2 py-1 transition-opacity duration-200 hover:opacity-75 focus:opacity-75" > {label} </a> ))} </nav> </div> <div className="border-t border-dashed border-gray/30 dark:border-white/30 px-4 py-4 md:px-8 text-sm text-center"> © {new Date().getFullYear()} Your Company </div> </footer> );}
使用方法
コンポーネントをインポートして、ページやレイアウトに組み込みます。logo
や navItems
を必要に応じて上書きしてください。
各フレームワークによってインポート先は調整し、実際には上記のコードを別ファイルで管理すると便利です。
// import Footer from "@/components/Footer";import Footer from "@/components/Footer";
export default function Layout({ children }) { return ( <> <main id="main">{children}</main> <Footer logo="MyWebsite" navItems={[ { label: "Privacy Policy", href: "/privacy" }, { label: "Terms of Service", href: "/terms" }, { label: "Contact", href: "/contact" }, ]} /> </> );}
import { colorPalette } from "@/styles/ColorPalette";import { typography } from "@/styles/Typography";import { LitElement, css, html } from "lit";import { customElement, property } from "lit/decorators.js";
type NavItem = { label: string; href: string;};
@customElement("my-footer")export class MyFooter extends LitElement { @property({ type: String }) logo?: string; @property({ type: Array }) navItems: NavItem[] = [ { label: "About", href: "/about" }, { label: "Contact", href: "/contact" }, { label: "Q&A", href: "/qa" }, ];
static styles = [ colorPalette, typography, css` :host { display: block; position: relative; margin-top: var(--spacing-8); background-color: var(--light-basic-white); color: var(--light-basic-black); font-family: var(--font-family-sans); } @media (prefers-color-scheme: dark) { :host { background-color: var(--dark-basic-black); color: var(--dark-basic-white); } } .gradient-line { position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: linear-gradient( to right, var(--basic-lime), var(--basic-teal), var(--basic-blue) ); } .footer-content { display: flex; flex-direction: column; align-items: center; padding: var(--spacing-6) var(--spacing-4); text-align: center; gap: var(--spacing-4); } @media (min-width: 768px) { .footer-content { flex-direction: row; justify-content: space-between; text-align: left; padding: var(--spacing-6) var(--spacing-8); } } .logo { font-size: var(--font-xl); font-weight: var(--font-bold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin: 0; } .nav { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--spacing-4); } @media (min-width: 768px) { .nav { justify-content: flex-end; gap: var(--spacing-8); } } .link { text-decoration: none; color: inherit; padding: var(--spacing-1) var(--spacing-2); transition: opacity 0.2s ease-in-out; } .link:hover, .link:focus { opacity: 0.75; } .border { border-top: 1px dashed var(--basic-gray); } @media (prefers-color-scheme: dark) { .border { border-top: 1px dashed var(--basic-white); } } .copyright { padding: var(--spacing-4); text-align: center; font-size: var(--font-sm); } @media (min-width: 768px) { .copyright { padding: var(--spacing-4) var(--spacing-8); } } `, ];
render() { return html` <footer> <div class="gradient-line"></div> <div class="footer-content" style=${!this.logo ? "justify-content: flex-end;" : ""} > ${this.logo ? html`<h2 class="logo">${this.logo}</h2>` : null} <nav class="nav"> ${this.navItems.map( (item) => html` <a class="link" href=${item.href}>${item.label}</a> `, )} </nav> </div> <div class="border"> <div class="copyright"> © ${new Date().getFullYear()} Your Company </div> </div> </footer> `; }}
使用方法
コンポーネントをインポートして、ページやレイアウトに組み込みます。logo
や navItems
を必要に応じて上書きしてください。
各フレームワークによってインポート先は調整し、実際には上記のコードを別ファイルで管理すると便利です。
// import "@/components/MyFooter";export class AppLayout extends HTMLElement { connectedCallback() { this.innerHTML = ` <main id="main"> <!-- 本文コンテンツ --> </main> <my-footer logo="MyAwesomeSite" .navItems="${JSON.stringify([ { label: 'Privacy Policy', href: '/privacy' }, { label: 'Terms of Service', href: '/terms' }, { label: 'Contact', href: '/contact' }, ])}" ></my-footer> `; }}