less-best-practices
保守性とモジュール性に優れたスタイルシートを実現するための、Less CSSのベストプラクティスとコーディングガイドラインを提供します。
description の原文を見る
Less CSS best practices and coding guidelines for maintainable, modular stylesheets
SKILL.md 本文
Less CSS ベストプラクティス
Less (Leaner Style Sheets)、CSS アーキテクチャ、メンテナンス可能なスタイルシート開発の専門家です。
主要原則
- 変数、ミックスイン、関数を活用したモジュール化された再利用可能な Less を書く
- 一貫性のある命名規則とファイル組織に従う
- 詳細度を低く保ち、過度に複雑なセレクターを避ける
- 可読性とメンテナンス性を優先する
ファイル構成
プロジェクト構造
less/
├── abstracts/
│ ├── variables.less # グローバル変数
│ ├── mixins.less # 再利用可能なミックスイン
│ └── functions.less # Less 関数
├── base/
│ ├── reset.less # CSS リセット/正規化
│ ├── typography.less # タイポグラフィ規則
│ └── base.less # 基本要素スタイル
├── components/
│ ├── buttons.less # ボタンコンポーネント
│ ├── cards.less # カードコンポーネント
│ └── forms.less # フォームコンポーネント
├── layout/
│ ├── header.less # ヘッダーレイアウト
│ ├── footer.less # フッターレイアウト
│ ├── grid.less # グリッドシステム
│ └── navigation.less # ナビゲーションレイアウト
├── pages/
│ ├── home.less # ホームページ固有
│ └── contact.less # コンタクトページ固有
├── themes/
│ └── default.less # デフォルトテーマ
├── vendors/
│ └── normalize.less # サードパーティスタイル
└── main.less # メインマニフェストファイル
メインマニフェスト
// main.less
// Abstracts
@import "abstracts/variables";
@import "abstracts/mixins";
@import "abstracts/functions";
// Vendors
@import "vendors/normalize";
// Base
@import "base/reset";
@import "base/typography";
@import "base/base";
// Layout
@import "layout/grid";
@import "layout/header";
@import "layout/navigation";
@import "layout/footer";
// Components
@import "components/buttons";
@import "components/cards";
@import "components/forms";
// Pages
@import "pages/home";
// Themes
@import "themes/default";
変数
命名規則
// variables.less
// 色 - セマンティック名を使用
@color-primary: #3498db;
@color-primary-light: lighten(@color-primary, 15%);
@color-primary-dark: darken(@color-primary, 15%);
@color-secondary: #2ecc71;
@color-text: #333333;
@color-text-muted: #666666;
@color-background: #ffffff;
@color-border: #e0e0e0;
@color-error: #e74c3c;
@color-success: #27ae60;
@color-warning: #f39c12;
@color-info: #17a2b8;
// タイポグラフィ
@font-family-base: 'Helvetica Neue', Arial, sans-serif;
@font-family-heading: 'Georgia', serif;
@font-family-mono: 'Consolas', monospace;
@font-size-base: 1rem;
@font-size-small: 0.875rem;
@font-size-large: 1.25rem;
@font-size-h1: 2.5rem;
@font-size-h2: 2rem;
@font-size-h3: 1.75rem;
@font-weight-normal: 400;
@font-weight-medium: 500;
@font-weight-bold: 700;
@line-height-base: 1.5;
@line-height-heading: 1.2;
// 間隔スケール
@spacing-unit: 8px;
@spacing-xs: (@spacing-unit * 0.5); // 4px
@spacing-sm: @spacing-unit; // 8px
@spacing-md: (@spacing-unit * 2); // 16px
@spacing-lg: (@spacing-unit * 3); // 24px
@spacing-xl: (@spacing-unit * 4); // 32px
@spacing-xxl: (@spacing-unit * 6); // 48px
// ブレークポイント
@breakpoint-sm: 576px;
@breakpoint-md: 768px;
@breakpoint-lg: 992px;
@breakpoint-xl: 1200px;
@breakpoint-xxl: 1400px;
// Z-index スケール
@z-index-dropdown: 1000;
@z-index-sticky: 1020;
@z-index-fixed: 1030;
@z-index-modal-backdrop: 1040;
@z-index-modal: 1050;
@z-index-popover: 1060;
@z-index-tooltip: 1070;
// トランジション
@transition-base: 0.3s ease;
@transition-fast: 0.15s ease;
@transition-slow: 0.5s ease;
// ボーダーラジウス
@border-radius-sm: 2px;
@border-radius-md: 4px;
@border-radius-lg: 8px;
@border-radius-pill: 50px;
@border-radius-circle: 50%;
// シャドウ
@shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
@shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
@shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
@shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);
// コンテナ幅
@container-sm: 540px;
@container-md: 720px;
@container-lg: 960px;
@container-xl: 1140px;
変数の補間
// プロパティ名を動的に使用する場合は補間を使用
@property: margin;
@position: top;
.element {
@{property}-@{position}: @spacing-md;
}
// 出力: margin-top: 16px;
ミックスイン
基本的なミックスイン
// mixins.less
// Clearfix
.clearfix() {
&::after {
content: '';
display: table;
clear: both;
}
}
// Flexbox ユーティリティ
.flex-center() {
display: flex;
align-items: center;
justify-content: center;
}
.flex-between() {
display: flex;
align-items: center;
justify-content: space-between;
}
.flex-column() {
display: flex;
flex-direction: column;
}
// 使用例
.container {
.flex-center();
min-height: 100vh;
}
パラメータ付きミックスイン
// パラメータを持つミックスイン
.button-variant(@bg-color, @text-color: white) {
background-color: @bg-color;
color: @text-color;
border: none;
&:hover {
background-color: darken(@bg-color, 10%);
}
&:active {
background-color: darken(@bg-color, 15%);
}
&:disabled {
background-color: lighten(@bg-color, 20%);
cursor: not-allowed;
}
}
// 使用例
.btn-primary {
.button-variant(@color-primary);
}
.btn-secondary {
.button-variant(@color-secondary);
}
.btn-danger {
.button-variant(@color-error);
}
レスポンシブミックスイン
// メディアクエリミックスイン
.respond-to(@breakpoint, @rules) {
@media (min-width: @breakpoint) {
@rules();
}
}
.respond-below(@breakpoint, @rules) {
@media (max-width: (@breakpoint - 1px)) {
@rules();
}
}
.respond-between(@min, @max, @rules) {
@media (min-width: @min) and (max-width: (@max - 1px)) {
@rules();
}
}
// 使用例
.element {
width: 100%;
.respond-to(@breakpoint-md, {
width: 50%;
});
.respond-to(@breakpoint-lg, {
width: 33.333%;
});
}
タイポグラフィミックスイン
.font-size(@size, @line-height: @line-height-base) {
font-size: @size;
line-height: @line-height;
}
.truncate(@lines: 1) when (@lines = 1) {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.truncate(@lines) when (@lines > 1) {
display: -webkit-box;
-webkit-line-clamp: @lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
// 見出しスタイル
.heading(@size) {
font-family: @font-family-heading;
font-size: @size;
font-weight: @font-weight-bold;
line-height: @line-height-heading;
margin-bottom: @spacing-md;
}
// 使用例
h1 {
.heading(@font-size-h1);
}
.card-title {
.truncate(2);
}
アクセシビリティミックスイン
.visually-hidden() {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.focus-visible() {
&:focus-visible {
outline: 2px solid @color-primary;
outline-offset: 2px;
}
}
// 使用例
.sr-only {
.visually-hidden();
}
.interactive-element {
.focus-visible();
}
BEM 命名規則
// Block Element Modifier パターン
.card {
// ブロックスタイル
background: @color-background;
border-radius: @border-radius-md;
box-shadow: @shadow-md;
overflow: hidden;
// 要素: ブロックの子
&__header {
padding: @spacing-md;
border-bottom: 1px solid @color-border;
}
&__title {
margin: 0;
font-size: @font-size-large;
font-weight: @font-weight-bold;
}
&__image {
width: 100%;
height: auto;
display: block;
}
&__body {
padding: @spacing-md;
}
&__footer {
padding: @spacing-md;
border-top: 1px solid @color-border;
background: lighten(@color-border, 5%);
}
// 修飾子: ブロックのバリエーション
&--featured {
border: 2px solid @color-primary;
}
&--horizontal {
display: flex;
.card__image {
width: 200px;
flex-shrink: 0;
}
}
&--compact {
.card__header,
.card__body,
.card__footer {
padding: @spacing-sm;
}
}
}
ネストルール
ネストは浅く保つ
// 悪い例: ネストが深すぎる
.nav {
.nav-list {
.nav-item {
.nav-link {
.nav-icon {
// 5段階 - 詳細度が高くなる
}
}
}
}
}
// 良い例: フラットな BEM 構造で浅いネスト
.nav {
display: flex;
align-items: center;
}
.nav__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.nav__item {
margin: 0 @spacing-sm;
}
.nav__link {
color: @color-text;
text-decoration: none;
transition: color @transition-base;
// 許可: 状態のネスト
&:hover,
&:focus {
color: @color-primary;
}
// 許可: 修飾子のネスト
&--active {
color: @color-primary;
font-weight: @font-weight-bold;
}
}
許可されるネストパターン
.component {
// 疑似要素
&::before,
&::after {
content: '';
position: absolute;
}
// 状態の疑似クラス
&:hover,
&:focus,
&:active {
// 状態スタイル
}
// BEM 修飾子
&--variant {
// 修飾子スタイル
}
// メディアクエリ
.respond-to(@breakpoint-md, {
// レスポンシブスタイル
});
}
関数
組み込み関数
// 色の関数
.element {
// ライトン/ダーケン
background: lighten(@color-primary, 20%);
border-color: darken(@color-primary, 10%);
// 彩度
color: saturate(@color-primary, 20%);
// 色の合成
background: mix(@color-primary, @color-secondary, 50%);
// フェード (不透明度)
background: fade(@color-primary, 50%);
// 色の抽出
@hue: hue(@color-primary);
@saturation: saturation(@color-primary);
@lightness: lightness(@color-primary);
}
// 数学関数
.element {
width: percentage(1/3); // 33.33333%
height: round(10.5px); // 11px
margin: ceil(4.2px); // 5px
padding: floor(4.8px); // 4px
font-size: abs(-10px); // 10px
z-index: min(5, 10, 3); // 3
z-index: max(5, 10, 3); // 10
}
// 文字列関数
@selector: e(".my-class"); // エスケープ
@path: %("url(%s)", "image.png"); // フォーマット
カスタム関数 (ミックスインを使用)
// Less は真の関数を持たないため、出力を持つミックスインを使用
.spacing(@multiplier) {
@result: (@spacing-unit * @multiplier);
}
// 変数スコープを使用した使用例
.element {
.spacing(3);
padding: @result; // 24px
}
// 代替案: 変数を直接使用
.padding(@multiplier) {
padding: (@spacing-unit * @multiplier);
}
.margin(@multiplier) {
margin: (@spacing-unit * @multiplier);
}
.element {
.padding(2);
.margin(1);
}
ループ
クラスの生成
// カラムクラスを生成
.generate-columns(@n, @i: 1) when (@i =< @n) {
.col-@{i} {
width: percentage(@i / @n);
}
.generate-columns(@n, (@i + 1));
}
// 使用例: .col-1 から .col-12 を生成
.generate-columns(12);
// 間隔ユーティリティを生成
.generate-spacing(@i: 0) when (@i =< 8) {
.m-@{i} {
margin: (@spacing-unit * @i);
}
.mt-@{i} {
margin-top: (@spacing-unit * @i);
}
.mb-@{i} {
margin-bottom: (@spacing-unit * @i);
}
.p-@{i} {
padding: (@spacing-unit * @i);
}
.pt-@{i} {
padding-top: (@spacing-unit * @i);
}
.pb-@{i} {
padding-bottom: (@spacing-unit * @i);
}
.generate-spacing((@i + 1));
}
.generate-spacing();
リストをループ
// 色リストを定義
@color-names: primary, secondary, success, danger, warning, info;
@color-values: @color-primary, @color-secondary, @color-success, @color-error, @color-warning, @color-info;
// 色ユーティリティを生成
.generate-colors(@names, @values, @i: 1) when (@i =< length(@names)) {
@name: extract(@names, @i);
@value: extract(@values, @i);
.text-@{name} {
color: @value;
}
.bg-@{name} {
background-color: @value;
}
.border-@{name} {
border-color: @value;
}
.generate-colors(@names, @values, (@i + 1));
}
.generate-colors(@color-names, @color-values);
ガード (条件分岐)
// ガード付きミックスイン
.button-size(@size) when (@size = small) {
padding: @spacing-xs @spacing-sm;
font-size: @font-size-small;
}
.button-size(@size) when (@size = medium) {
padding: @spacing-sm @spacing-md;
font-size: @font-size-base;
}
.button-size(@size) when (@size = large) {
padding: @spacing-md @spacing-lg;
font-size: @font-size-large;
}
// 使用例
.btn-sm {
.button-size(small);
}
.btn-md {
.button-size(medium);
}
.btn-lg {
.button-size(large);
}
// 比較演算子を使用したガード
.set-color(@lightness) when (@lightness > 50%) {
color: black;
}
.set-color(@lightness) when (@lightness =< 50%) {
color: white;
}
名前空間化
// 関連するミックスインをグループ化
#utils {
.clearfix() {
&::after {
content: '';
display: table;
clear: both;
}
}
.visually-hidden() {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
}
#buttons {
.base() {
display: inline-flex;
align-items: center;
border: none;
cursor: pointer;
transition: all @transition-base;
}
.primary() {
#buttons.base();
background: @color-primary;
color: white;
}
}
// 使用例
.container {
#utils.clearfix();
}
.btn-primary {
#buttons.primary();
}
パフォーマンスのベストプラクティス
- 深くネストされたセレクターを避ける (最大 3 レベル)
- 詳細度を低く保つ - 単一のクラスセレクターを優先
!importantを使用しない (ユーティリティのオーバーライドを除く)- ベンダープレフィックス用にミックスインを使用 (または autoprefixer)
extendの使用を最小化 (ファイルサイズが増加する可能性)- 本番環境では圧縮 CSS にコンパイル
- 開発時のみソースマップを有効化
コードスタイルガイドライン
- インデントには 2 スペースを使用
- 文字列には単一引用符を使用
- 宣言のコロン後にスペースを追加
- 開き中括弧の前にスペースを追加
- 閉じ中括弧を新しい行に配置
- ルールセットを空白行で区切る
- 複雑なロジックにはコメントを追加
- プロパティを一貫して並べる
プロパティ順序
.element {
// ポジショニング
position: relative;
top: 0;
right: 0;
z-index: @z-index-dropdown;
// 表示とボックスモデル
display: flex;
flex-direction: column;
width: 100%;
max-width: @container-md;
padding: @spacing-md;
margin: @spacing-sm auto;
// タイポグラフィ
font-family: @font-family-base;
font-size: @font-size-base;
font-weight: @font-weight-normal;
line-height: @line-height-base;
color: @color-text;
text-align: left;
// ビジュアル
background-color: @color-background;
border: 1px solid @color-border;
border-radius: @border-radius-md;
box-shadow: @shadow-sm;
// アニメーション
transition: all @transition-base;
// その他
cursor: pointer;
overflow: hidden;
}
ライセンス: Apache-2.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- mindrally
- リポジトリ
- mindrally/skills
- ライセンス
- Apache-2.0
- 最終更新
- 不明
Source: https://github.com/mindrally/skills / ライセンス: Apache-2.0
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。