2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactMarkDownでimgタグを使用するときの注意点

Last updated at Posted at 2025-03-03

ReactMarkdown の img タグのカスタムコンポーネントでの課題と解決策を書いてみました。

ニッチな内容ですが、公式にもイシューによく上がっているにも関わらずあまり記事がなかったのでまとめてみました。

1. 背景

ReactMarkdown を利用して Markdown を HTML に変換する際、画像(img タグ)をカスタマイズしたい場面があります。

この例でいうと、写真にフォーカスすると
image.png

マウスをかざしたとき、グレーのオーバーレイをさせるときの対応をimgタグに実装したかった。

image.png

このときにdivをつかってオーバーレイを実装していました。

しかし、ReactMarkdown はデフォルトで img<p> タグでラップする仕様があり、これが原因で以下の問題が発生しました。

  • 画像の上に hover のオーバーレイを表示したいが、p の影響を受ける
  • ::after::before を使った hover のオーバーレイが適用されない
  • p タグ内に div を追加すると HTML 構造が壊れる
  • p タグを変更せずに img のみをカスタマイズする方法が不明

この問題を ReactMarkdown のカスタムコンポーネントのみで解決する方法を検討しました。


2. 問題点

ReactMarkdown のデフォルト動作

ReactMarkdown は以下のように、img タグを <p> の内部に配置します。

import ReactMarkdown from 'react-markdown';

const markdown = `![サンプル画像](https://example.com/sample.jpg)`;

<ReactMarkdown>{markdown}</ReactMarkdown>;

➡ 生成される HTML

<p>
  <img src="https://example.com/sample.jpg" alt="サンプル画像" />
</p>

p タグの影響を受けるため、自由に img を加工できない問題が発生しました。

公式やイシューを見ると、MDでの写真は段落として表示するため、pタグで囲む思想のようでした。


::before::after を使った hover オーバーレイが機能しない

通常の div なら ::before を使ってオーバーレイを表示できますが、img タグは 空要素 のため、::before::after は適用されません。

const StyledImage = styled.img`
  position: relative;
  
  &:hover::before {
    content: 'クリックして拡大';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-size: 16px;
    background: rgba(0, 0, 0, 0.5);
    padding: 8px 12px;
    border-radius: 4px;
  }
`;

img タグでは ::before::after が無視されるため、オーバーレイが表示されない


div を追加すると HTML 構造が壊れる

imgdiv でラップすれば hover のオーバーレイを実装できますが、ReactMarkdownp タグを変更しないため、HTML が壊れてしまいます。

const CustomImage = ({ src, alt }: { src?: string; alt?: string }) => {
  return (
    <div>
      <img src={src} alt={alt} />
      <span>クリックして拡大</span>
    </div>
  );
};

<ReactMarkdown components={{ img: CustomImage }}>{markdown}</ReactMarkdown>;

p タグの中に div が入るため、不正な HTML 構造になる


3. 解決策

box-shadow を使って hover 時にオーバーレイを適用

img 自体に box-shadow を適用し、hover した際に擬似オーバーレイを表示する方法が最適でした。

const StyledImage = styled.img`
  max-width: 100%;
  height: auto;
  display: block;
  cursor: pointer;
  transition: filter 0.3s ease-in-out, box-shadow 0.3s ease-in-out;

  &:hover {
    filter: brightness(50%);
    box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.5);
  }
`;

filter: brightness(50%) で画像を暗くし、box-shadow でオーバーレイを再現


span を使って hover テキストを表示

div ではなく span を使い、img の隣にテキストを配置することで、p の影響を受けずに hover オーバーレイを適用できます。

const OverlayText = styled.span`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-size: 16px;
  font-weight: bold;
  background: rgba(0, 0, 0, 0.5);
  padding: 8px 12px;
  border-radius: 4px;
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
  pointer-events: none;
`;

const ImageWrapper = styled.span`
  position: relative;
  display: inline-block;
  cursor: pointer;

  &:hover ${OverlayText} {
    opacity: 1;
  }
`;

p の影響を受けず、imghover に対応


4. まとめ

ReactMarkdownimg カスタマイズの問題

  • img タグが デフォルトで p にラップされる
  • ::before::afterimg では使えない
  • div を追加すると HTML 構造が崩れる
  • hover のオーバーレイが 表示されない

解決策

box-shadowfilter を利用し、img 単体で hover を適用
span を利用し、テキストオーバーレイを hover 時に表示
p タグを変更せず、HTML の構造を維持

この方法を採用することで、ReactMarkdownimg タグを hover 可能にし、HTML の構造を壊さずにオーバーレイを適用することが可能になった

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?