ガイド

cursor: not-allowedとは?効かない原因・Bootstrap・Tailwindでの使い方を完全解説【2026年最新】

室谷東吾
監修者室谷東吾(@0x__tom

株式会社MYUUU 代表取締役 / 日本最大級AIコミュニティ「.AI」創設者(累計2,000名超)/ セプテーニ・ホールディングス(電通グループ)と資本業務提携 / 著書「お金を使わず、AIを働かせる『Dify』活用」(ぱる出版、3刷)/ Xフォロワー約2万人

テキトー教師
監修者テキトー教師(@tekitoo_T_cher

.AI 認定講師 / 教育×AIの専門家 / 累計300名以上にAI活用を指導 / 「テキトーに学ぶ」がモットーの実践派講師 / Xアカウント

cursor: not-allowedとは?効かない原因・Bootstrap・Tailwindでの使い方を完全解説【2026年最新】

cursor: not-allowedとは?使えない・効かない原因から、CSS・Bootstrap・Tailwindの実装まで完全解説【2026年最新】

室谷室谷
今回は cursor: not-allowed の話をしましょう。これ、CSSの中でも「なぜか効かない」ってなりやすいプロパティで、.AI(ドットエーアイ)のコミュニティでもフロントエンド系の話題でよく出てくるんですよね。
テキトー教師テキトー教師
そうなんですよ。講座でHTML/CSSを教えていると、特に「ボタンのdisabled状態を見た目で伝えたい」という場面でハマる人が多いです。

「書いたはずなのにカーソルが変わらない」って。
室谷室谷
仕組みを理解していないとデバッグに何時間もかかることがあります。実際MYUUUでも昔、Bootstrapを使ったプロジェクトで「disabledボタンにカーソルが効かない」問題が出て、なんでだろうと調べた記憶があります・・・
テキトー教師テキトー教師
BootstrapとTailwindで挙動が違うのが特にわかりにくいですよね。この記事では cursor: not-allowed の基本から、よくある「効かない」パターンの原因と解決策、フレームワーク別の実装方法まで全部まとめていきます。

cursor: not-allowedの基本

MDN Web Docsのcursorプロパティリファレンスページ(公式サイトより)

室谷室谷
まず基本から確認しましょう。cursor: not-allowed というのは、CSSの cursor プロパティの値のひとつです。

要素の上にマウスを乗せたとき、「この操作は許可されていません」を示す禁止マークのカーソルを表示します。
テキトー教師テキトー教師
MDNの定義だと「要求された操作が受け付けられないことを示す」という説明になっています。見た目は丸に斜線が入った禁止アイコンですね。
室谷室谷
使う場面は主に3つです。無効化されたボタン、操作できないフォーム要素、そしてドラッグ不可のエリア。

ユーザーに「ここはクリックできないよ」と直感的に伝える役割です。
テキトー教師テキトー教師
UIのフィードバックとして重要なんですよ。グレーアウトだけだと気づかない人もいるので、カーソルの形で「操作不可」を伝えるのはアクセシビリティ的にも意味があります。

基本的な書き方

基本的な記述はシンプルです。

.disabled-button {
  cursor: not-allowed;
}

HTML側と組み合わせると、こうなります。

<button class="disabled-button" disabled>送信できません</button>
室谷室谷
ただしこの「シンプルな書き方」が、実はBootstrapやTailwindを使うと素直に動かないケースがある。ここが今日の本題です。
テキトー教師テキトー教師
CSSの cursor プロパティ自体は全モダンブラウザで問題なく動きます。MDNの互換性データを見ると、Chrome・Firefox・Safari・Edgeで完全対応しています。

問題はフレームワークが pointer-events: none を一緒に設定するせいで打ち消されることなんですよね。

cursor: not-allowedが効かない原因と解決策

室谷室谷
ここが一番重要です。「cursor: not-allowed を書いたのにカーソルが変わらない」という問題の原因は、ほぼ100%これです・・・
テキトー教師テキトー教師
pointer-events: none ですね。
室谷室谷
そうです。pointer-events: none が設定されていると、ブラウザはその要素を「マウスイベントの対象外」として扱います。

結果として、cursor プロパティも無視されてしまう。
テキトー教師テキトー教師
コミュニティのメンバーさんが引っかかるのもまさにここですね。Bootstrapの disabled クラスやTailwindの disabled: ステートがデフォルトで pointer-events: none を設定しているので、その上に cursor: not-allowed を書いても効かない。

pointer-eventsとcursorの関係

pointer-events: noneとcursor: not-allowedの関係図:効かないパターンと動くパターンの比較

これを理解するには、pointer-events プロパティの仕組みを知る必要があります。

/* これを設定すると cursor の変更が無効になる */
.disabled {
  pointer-events: none;
  cursor: not-allowed; /* ← 効かない! */
}
室谷室谷
pointer-events: none は「マウスの存在を無視する」という設定なんですよ。要素がマウスに対して透明になるイメージです。

カーソルスタイルを変えるためには、まずマウスの存在を要素が認識している必要がある。
テキトー教師テキトー教師
なるほど、という感じで。では解決策はどうなるか。
室谷室谷
2つのアプローチがあります。
テキトー教師テキトー教師
まとめるとこういう構造です。
  1. pointer-events: none を外して cursor: not-allowed だけにする(クリックは JavaScript で防ぐ)
  2. 親要素に cursor: not-allowed を設定して、子要素に pointer-events: none を設定する
室谷室谷
コードで見るとわかりやすいですね。
/* アプローチ1: pointer-events を使わない */
button:disabled {
  cursor: not-allowed;
  pointer-events: auto; /* デフォルト値に戻す */
}

/* アプローチ2: 親子で分担する */
.wrapper {
  cursor: not-allowed;
}
.wrapper button:disabled {
  pointer-events: none;
}
テキトー教師テキトー教師
アプローチ1は「ボタンのクリックをJavaScriptで止める」か「HTML の disabled 属性に依存する」前提ですね。アプローチ2が特に有効なのは、Bootstrapのように既存の pointer-events: none を変えたくない場合です。
室谷室谷
MYUUUのプロジェクトで使うのはだいたいアプローチ2ですね。既存のフレームワークに手を入れすぎないようにするために。

button disabled cursor not-allowedの問題

テキトー教師テキトー教師
<button disabled> のケースは特別に説明が必要です。HTML の disabled 属性がついているボタンは、ブラウザのデフォルトスタイルで既に pointer-events: none になっているブラウザもあります。
室谷室谷
だから button:disabled { cursor: not-allowed; } と書いても、ブラウザによって効いたり効かなかったりする。Chromeでは効かないケースが多いですね・・・
テキトー教師テキトー教師
そこでよく使われるのが、HTMLの disabled 属性を外して、代わりにCSSクラスで無効化する方法です。
<!-- HTMLのdisabled属性を使わない場合 -->
<button class="btn-disabled" aria-disabled="true">送信</button>
.btn-disabled {
  cursor: not-allowed;
  opacity: 0.6;
  /* pointer-events はつけない */
}
室谷室谷
aria-disabled="true" をつけることでスクリーンリーダーにも「無効なボタン」として認識させられます。アクセシビリティも担保できるのが良いですね。
テキトー教師テキトー教師
ただし pointer-events を外すとクリックイベントが発火してしまうので、JavaScript側でイベントを止める処理が必要です。
document.querySelector(".btn-disabled").addEventListener("click", (e) => {
  e.preventDefault();
  // クリック時は何もしない
});
室谷室谷
この辺りのトレードオフを理解しておくと、フレームワーク別の実装も理解しやすくなります。

Bootstrap 4/5でのcursor: not-allowedの設定方法

テキトー教師テキトー教師
Bootstrapを使っている人が一番詰まるのがここです。Bootstrap 4以降、disabled 状態のボタンとリンクに pointer-events: none がデフォルトで設定されています。
室谷室谷
BootstrapのGitHub Issueにも長年議論がありましたよ。「cursor: not-allowed が効かないのはバグじゃないか」という報告が複数あって、Bootstrapチームの回答は「意図的な仕様だ」という感じでした・・・
テキトー教師テキトー教師
そうなんです。Bootstrapはブラウザのネイティブな disabled スタイルに寄せる方向で設計されているので、pointer-events: none を設定することでクリックを無効化しています。

結果として cursor: not-allowed を上書きできない。

Bootstrap 5での解決策

<!-- Bootstrap 5のdisabledボタン -->
<button type="button" class="btn btn-primary" disabled>無効なボタン</button>

Bootstrap 5 で cursor: not-allowed を表示するには、カスタムCSSで上書きします。

/* Bootstrap 5 でカーソルを上書きする方法1: pointer-events を戻す */
button:disabled,
button.disabled {
  pointer-events: auto !important;
  cursor: not-allowed !important;
}
室谷室谷
!important を使うのは気持ち悪いんですよね・・・。Bootstrapの仕様を壊してしまう可能性もある。
テキトー教師テキトー教師
そこで推奨されるのが「ラッパー要素を使う方法」です。Bootstrapのドキュメントでも触れられています。
<!-- 親にcursorを設定する方法 -->
<span style="cursor: not-allowed;" class="d-inline-block">
  <button type="button" class="btn btn-primary" disabled style="pointer-events: none;">
    無効なボタン
  </button>
</span>
テキトー教師テキトー教師
親の <span>cursor: not-allowed を設定し、ボタン自体は pointer-events: none のままにする。これでBootstrapの設計を壊さずに禁止カーソルを表示できます。
室谷室谷
CSSクラスで管理すれば再利用もできますね。
/* 再利用可能なラッパークラス */
.cursor-not-allowed-wrapper {
  cursor: not-allowed;
  display: inline-block;
}

.cursor-not-allowed-wrapper [disabled] {
  pointer-events: none;
}

Bootstrap 4でのcursor not-allowed

Bootstrap 4 は基本的に Bootstrap 5 と同じアプローチが有効です。ただし Bootstrap 4 のバージョンによってスタイルが微妙に異なるため、DevToolsで当たっているスタイルを確認しながら調整するのが確実です。

テキトー教師テキトー教師
.not-allowed というカスタムクラスを作っておくのも手ですよ。
/* Bootstrap 4/5 共通のカスタムクラス */
.not-allowed {
  cursor: not-allowed !important;
}
室谷室谷
pointer-events: auto に戻した場合は、クリックイベントが発火するのでJavaScript側での制御も必要になることを忘れずに。

TailwindCSSでのcursor-not-allowedの使い方

Tailwind CSSのcursor utilities - cursor-not-allowedクラスの使用例(公式サイトより)

室谷室谷
TailwindCSSは非常にシンプルです。cursor-not-allowed というユーティリティクラスが用意されていて、これを要素に追加するだけです。
<button class="cursor-not-allowed opacity-50" disabled>
  無効なボタン
</button>
テキトー教師テキトー教師
Tailwindの良いところは、このクラス名がそのままCSSの cursor: not-allowed; に対応しているので、直感的にわかりますよね。
室谷室谷
ただしTailwindでも同じ問題があります。disabled: バリアントでボタンを無効化すると、pointer-events-none が一緒に設定されることがあって・・・
テキトー教師テキトー教師
そこで使うのが disabled:cursor-not-alloweddisabled:pointer-events-auto の組み合わせです。
<!-- Tailwind CSS v3/v4 でdisabled状態を管理 -->
<button
  class="bg-blue-500 text-white px-4 py-2 
         disabled:opacity-50 
         disabled:cursor-not-allowed"
  disabled
>
  送信
</button>
室谷室谷
ただし disabled:cursor-not-allowed も、pointer-events-none が効いている場合は動かないことがあります。そのときは:
<button
  class="bg-blue-500 text-white px-4 py-2 
         disabled:opacity-50 
         disabled:cursor-not-allowed
         disabled:pointer-events-auto"
  disabled
>
  送信
</button>
テキトー教師テキトー教師
pointer-events-auto を明示することで pointer-events: none を上書きできます。

tailwind cursor not allowed not workingの対処法

テキトー教師テキトー教師
講座で「Tailwindで cursor-not-allowed が動かない」という相談をよく受けます。原因のパターンをまとめるとこうなります。
  1. Tailwind の disabled: バリアントの優先度が pointer-events の設定に勝っていない
  2. Tailwindのバージョンによって動作が異なる
  3. Purge設定でクラスが削除されている(v2以前)
室谷室谷
Purge問題は最近は減りましたが、念のためです。解決策は tailwind.config.js のコンテンツ設定にクラスが含まれているか確認することです。
テキトー教師テキトー教師
v3以降はJITモードがデフォルトなので、コンテンツファイルにクラスが含まれていれば自動的に生成されます。
// tailwind.config.js
module.exports = {
  content: [
    "./src/**/*.{html,js,jsx,ts,tsx}",
  ],
  // ...
}
室谷室谷
Tailwind v4ではCSS Firstの設定方式になりました。
/* tailwind.config.css (v4) */
@import "tailwindcss";
@source "./src/**/*.{html,js,jsx,ts,tsx}";
テキトー教師テキトー教師
どのバージョンを使っているかを確認してから対処法を探すのが大事ですね。

tailwind disabled buttonへの応用

室谷室谷
Tailwindでdisabledなボタンを作る完全なパターンを見ておきましょう。
<!-- Tailwind の disabled ボタンの完全パターン -->
<button
  class="
    bg-blue-600 hover:bg-blue-700
    text-white font-semibold
    px-6 py-2 rounded-lg
    transition-colors duration-200
    disabled:bg-gray-400
    disabled:text-gray-200
    disabled:cursor-not-allowed
    disabled:pointer-events-auto
    disabled:opacity-60
  "
  disabled
>
  送信する
</button>
テキトー教師テキトー教師
disabled:pointer-events-auto を入れることで cursor-not-allowed が確実に表示されます。hover:bg-blue-700 はdisabled時には pointer-events-none 相当になるので、hover状態にならないから問題ありません。
室谷室谷
これが実践でよく使うパターンですね。MYUUUのプロジェクトでも似たような実装をしています。

cursor: not-allowedをReactで使う方法

室谷室谷
ReactやNext.jsでも同じCSSの問題が起きます。インラインスタイルやstyled-componentsを使う場合も見ておきましょう。
テキトー教師テキトー教師
Reactではインラインスタイルが使いやすいので、pointer-events の問題を含めた書き方を確認しておくと安心です。

Reactでのインラインスタイル

// React のインラインスタイルで cursor: not-allowed
const DisabledButton = ({ isDisabled, onClick, children }) => {
  return (
    <button
      onClick={isDisabled ? undefined : onClick}
      style={{
        cursor: isDisabled ? "not-allowed" : "pointer",
        opacity: isDisabled ? 0.6 : 1,
        pointerEvents: isDisabled ? "auto" : undefined,
      }}
      disabled={isDisabled}
    >
      {children}
    </button>
  );
};
室谷室谷
インラインスタイルで pointerEvents: "auto" を設定することで、HTMLの disabled 属性が設定していた pointer-events: none を上書きできます。
テキトー教師テキトー教師
ただしこの場合、disabled 属性がついているのにクリックできてしまう(JavaScriptのイベントは発火する)ので、onClick の条件分岐が必要です。onClick={isDisabled ? undefined : onClick} という形で制御しています。
室谷室谷
styled-components や emotion を使う場合は、CSSと同じアプローチが使えます。
// styled-components での実装
import styled from "styled-components";

const Button = styled.button`
  cursor: pointer;
  background-color: #3b82f6;
  color: white;
  padding: 8px 16px;
  border-radius: 6px;
  border: none;

  &:disabled {
    cursor: not-allowed;
    pointer-events: auto;
    opacity: 0.6;
    background-color: #9ca3af;
  }
`;
テキトー教師テキトー教師
styled-componentsならCSSのセレクタをそのまま書けるので、:disabled 擬似クラスも普通に使えます。

react cursor pointerとの使い分け

室谷室谷
cursor: not-allowed の対になる値として cursor: pointer があります。インタラクティブな要素にはpointerを、操作不可の要素にはnot-allowedを使うのが基本です。
テキトー教師テキトー教師
意外と設定していないコードが多いんですよ。デフォルトのカーソルのまま「クリックできるけど矢印のまま」という状態になっている。
/* 基本の使い分け */
.clickable {
  cursor: pointer;    /* クリックできる要素 */
}

.disabled {
  cursor: not-allowed; /* 操作不可の要素 */
}

.draggable {
  cursor: grab;        /* ドラッグできる要素 */
}

.dragging {
  cursor: grabbing;    /* ドラッグ中 */
}
室谷室谷
UIの細部まで気を配ると、ユーザー体験が全然違いますよね・・・。これは地味だけど重要です。

cursor: not-allowedとpointer-events: noneを同時に使う方法

テキトー教師テキトー教師
cursor: not-allowed でカーソルを変えつつ、クリックも無効にしたい」という要件はよくあります。これを素直に書くと:
.disabled {
  cursor: not-allowed;
  pointer-events: none; /* ← これで cursor も無効になってしまう */
}

と書きたくなりますが、前述の通りこれは機能しません。

室谷室谷
「両方やりたい」というのは技術的に矛盾しているんですよね。pointer-events: none は「マウスイベントを受け取らない」という意味なので、カーソルスタイルも「受け取らない」状態になる・・・
テキトー教師テキトー教師
そこで有効なのが「ラッパー要素で分担する」方法です。
<div class="cursor-wrapper" style="cursor: not-allowed; display: inline-block;">
  <button
    disabled
    style="pointer-events: none; opacity: 0.5;"
  >
    クリック不可
  </button>
</div>
室谷室谷
親要素が cursor: not-allowed を担当して、子要素が pointer-events: none でクリックをブロックする。それぞれの役割を分離するわけですね。
テキトー教師テキトー教師
この「ラッパー要素で分担」がシンプルで確実な解決策です。
/* CSSクラスで再利用可能にする */
.not-allowed-wrapper {
  cursor: not-allowed;
  display: inline-block; /* または inline-flex */
}

.not-allowed-wrapper > * {
  pointer-events: none;
}
室谷室谷
これをコンポーネントとして切り出しておくと、Reactプロジェクトでも便利です。
// 再利用可能なNotAllowedWrapperコンポーネント
const NotAllowedWrapper = ({ children, disabled }) => {
  if (!disabled) return <>{children}</>;
  
  return (
    <span
      style={{
        cursor: "not-allowed",
        display: "inline-block",
      }}
    >
      <span style={{ pointerEvents: "none" }}>
        {children}
      </span>
    </span>
  );
};

// 使用例
<NotAllowedWrapper disabled={isLoading}>
  <button>送信</button>
</NotAllowedWrapper>
テキトー教師テキトー教師
このパターン、ハマる人が多いのでよく紹介しています。一度覚えると応用が利くので。

cursor: not-allowedのCSS詳細:cursorプロパティ全体を理解する

室谷室谷
cursor: not-allowed をより深く理解するために、cursor プロパティ全体の仕組みを見ておきましょう。MDNの仕様を確認すると、cursor プロパティのフォールバック機能が興味深いです。
テキトー教師テキトー教師
カスタム画像と組み合わせられるんですよね。
/* カスタムカーソル画像 + フォールバック */
.custom-cursor {
  cursor: url("custom-not-allowed.svg"), not-allowed;
}
室谷室谷
URLが読み込めない場合は not-allowed にフォールバックするという設計です。カスタムカーソルを使うUIでも not-allowed が確実に表示できます。

cursor pngとcursor svgでカスタム禁止カーソルを作る

テキトー教師テキトー教師
カスタムカーソル画像として使えるフォーマットは主にPNGとSVGです。CSSの cursor プロパティにURLを渡す形になります。
/* PNG ファイルのカスタムカーソル */
.custom-not-allowed {
  cursor: url("not-allowed-icon.png") 12 12, not-allowed;
}

/* SVG ファイルのカスタムカーソル */
.custom-not-allowed-svg {
  cursor: url("not-allowed-icon.svg") 12 12, not-allowed;
}
室谷室谷
url() の後にある 12 12 がホットスポットの座標です。カーソル画像のどこを「クリックポイント」にするかを指定します。

左上が 0 0 で、中央付近を指定するのが一般的ですね。
テキトー教師テキトー教師
ブラウザが推奨するカーソル画像のサイズは最大32×32ピクセルです。MDNには「128×128ピクセルが上限(Firefox・Chromium)」と記載されていますが、実用的には32×32以内が安全です。
室谷室谷
SVGのカーソルは解像度に依存しないので、Retinaディスプレイでも綺麗に表示されます。ただしSVGカーソルへの対応がブラウザによって異なるので、PNGをフォールバックに入れるのが無難です・・・
/* SVG → PNG → キーワード のフォールバック */
.cursor-custom {
  cursor: 
    url("icon.svg") 12 12,
    url("icon.png") 12 12,
    not-allowed;
}

disabled cursorの種類一覧

テキトー教師テキトー教師
not-allowed 以外にも「操作不可」を伝えるカーソルがあります。用途によって使い分けが大事です。

まとめるとこういう対応になります。

CSSの値用途見た目
not-allowed操作が許可されていない丸に斜線
no-dropドロップ不可の場所に来た似た禁止アイコン(Firefoxはnot-allowedと同じ)
defaultデフォルト状態矢印
noneカーソル非表示見えない
wait処理中で操作不可砂時計・スピナー
progress処理中だが操作可能砂時計+矢印
室谷室谷
no-dropnot-allowed は視覚的に似ていますが、意味が違います。no-drop はドラッグ&ドロップ操作で「ここにはドロップできない」を示す。

not-allowed は「この操作全般が不可」というより広い意味です。
テキトー教師テキトー教師
MDNのドキュメントを見ると「WindowsとmacOSでは no-dropnot-allowed と同じになる」とある。ブラウザ間で表示が微妙に異なることがあるので、厳密な使い分けが必要な場合は注意です。

cursor not allowedとCSS disabled:アクセシビリティの考慮

室谷室谷
カーソルを変えるだけでは不十分で、アクセシビリティも考える必要があります。視覚的なフィードバックだけに頼ると、スクリーンリーダーユーザーに情報が届かない・・・
テキトー教師テキトー教師
その通りです。cursor: not-allowed はあくまで視覚的なヒントで、スクリーンリーダーはカーソルの形を読み上げません。
室谷室谷
なので aria-disabled="true" をセットで設定するのが正解です。
<!-- アクセシビリティを考慮したdisabled要素 -->
<button
  aria-disabled="true"
  tabindex="-1"
  style="cursor: not-allowed; opacity: 0.6;"
  onclick="return false;"
>
  送信できません
</button>
テキトー教師テキトー教師
tabindex="-1" を設定することで、Tabキーでのフォーカスも防げます。aria-disabled="true" はスクリーンリーダーに「この要素は無効です」と伝えます。
室谷室谷
HTMLの disabled 属性を使う場合は自動的にスクリーンリーダーに伝わります。ただし前述の通り、pointer-events との兼ね合いでカーソルが変わらない問題が出るので、どちらを優先するか設計段階で決めておく方が良いですね。

cursor: not-allowedの実装例:よくある使用シーン

テキトー教師テキトー教師
実際のプロジェクトでよく使う場面を見ていきましょう。

フォームの送信ボタン(送信中)

室谷室谷
ローディング中に再送信を防ぐ実装は、エンジニアなら必ず必要になりますよね。
// React: 送信中は cursor-not-allowed
const SubmitButton = () => {
  const [isLoading, setIsLoading] = useState(false);
  
  const handleSubmit = async () => {
    setIsLoading(true);
    try {
      await submitForm();
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <button
      onClick={handleSubmit}
      disabled={isLoading}
      style={{
        cursor: isLoading ? "not-allowed" : "pointer",
        pointerEvents: "auto",
        opacity: isLoading ? 0.7 : 1,
      }}
    >
      {isLoading ? "送信中..." : "送信"}
    </button>
  );
};
テキトー教師テキトー教師
この実装では disabled={isLoading} でHTMLのフォーム送信を止めつつ、pointer-events: auto でカーソルスタイルを有効にしています。

権限がない機能のグレーアウト

室谷室谷
SaaSアプリでよくある「このプランではこの機能は使えません」というUI。MYUUUのサービスでも使っています。
// プラン制限による無効化
const FeatureButton = ({ isPremiumFeature, hasPremium }) => {
  const isDisabled = isPremiumFeature && !hasPremium;
  
  return (
    <div
      style={{
        display: "inline-block",
        cursor: isDisabled ? "not-allowed" : "default",
      }}
    >
      <button
        style={{
          pointerEvents: isDisabled ? "none" : "auto",
          opacity: isDisabled ? 0.5 : 1,
        }}
        onClick={isDisabled ? undefined : handleClick}
      >
        {isPremiumFeature && !hasPremium && (
          <span className="badge">PRO</span>
        )}
        高度な分析を見る
      </button>
    </div>
  );
};
テキトー教師テキトー教師
ラッパー div が cursor: not-allowed を持って、内側の button が pointer-events: none でクリックをブロックするパターンですね。ユーザーには「このボタンは押せない」と伝えつつ、クリックイベントも発火しない。

よくある質問(FAQ)

室谷室谷
最後によくある疑問をまとめておきましょう。

Q: cursor: not-allowedとcursor: defaultの違いは?

テキトー教師テキトー教師
cursor: default はプラットフォームの標準カーソル(通常は矢印)を表示します。cursor: not-allowed は明示的に「操作不可」を示す禁止マークを表示します。

無効化された要素でも単純に矢印を表示したいだけなら default、「ここは押せません」とユーザーに明示したいなら not-allowed を使います。

Q: cursor: not-allowedはiPhoneやAndroidでも効く?

室谷室谷
スマートフォンはタッチデバイスなのでマウスカーソル自体が存在しません。cursor: not-allowed はPC/デスクトップのみ有効で、スマートフォンでは無視されます。

モバイルでの操作不可状態は、視覚的スタイル(グレーアウト、opacity)で表現する必要があります。

Q: CSSの disabled 擬似クラスとnot-allowedを組み合わせる方法は?

テキトー教師テキトー教師
input:disabledbutton:disabledといったCSS擬似クラスと組み合わせられます。
input:disabled,
button:disabled,
select:disabled {
  cursor: not-allowed;
  pointer-events: auto; /* HTMLのdisabledによる制限を解除 */
  opacity: 0.6;
}
室谷室谷
ただし pointer-events: auto にすると、HTMLの disabled 属性があってもJavaScriptのイベントが発火する可能性があります。フォームの場合はHTMLの disabled がサーバーサイドの検証でも機能するので、その点を理解した上で実装する必要があります。

Q: Bootstrapのdisabledクラスとdisabled属性はどう違う?

テキトー教師テキトー教師
Bootstrapでは HTMLの disabled 属性と .disabled CSSクラスの2つの無効化方法があります。フォームコントロール(<input><button>)には通常 disabled 属性を使い、リンク(<a>)には .disabled クラスと tabindex="-1" を組み合わせます。

どちらでも pointer-events: none が設定されますが、スクリーンリーダーへの伝わり方が異なります。

まとめ

室谷室谷
今回の cursor: not-allowed の話、かなり深掘りしましたね。一言でいうと「pointer-events: none と同時に使えない」というのが核心です。
テキトー教師テキトー教師
この点を理解していると、BootstrapでもTailwindでも自信を持って実装できます。受講生さんが詰まるのは「なぜ効かないのか」がわからないからで、一度理解すれば怖くないです。
室谷室谷
ポイントをまとめるとこうなります。
  • cursor: not-allowedpointer-events: none と同時に使えない
  • Bootstrap 4/5 の disabled 要素は pointer-events: none を持っているので、ラッパー要素で回避する
  • Tailwind では disabled:cursor-not-alloweddisabled:pointer-events-auto を組み合わせる
  • アクセシビリティのために aria-disabled="true"tabindex="-1" もセットで設定する
  • カスタムカーソル画像(PNG/SVG)と組み合わせる場合はフォールバックを忘れずに
テキトー教師テキトー教師
「効かない」という経験をした人ほど、この記事の内容が身に染みると思います。実装で詰まったらこの記事に戻ってきてください。
室谷室谷
BootstrapやTailwindを使う以上、こういう「フレームワークの仕様と戦う」場面は必ず出てきます。そのときに「なぜそうなっているか」を理解していると、解決が早い。

MYUUUでも「フレームワークを使いこなす」という視点は常に大事にしています。

出典

.AI TIMES一覧に戻る