🤷‍♂️

MDsveX プラグイン + Tailwind CSS .prose で 期待する見た目にならない問題

2024-12-30 00:00

本ブログサイトを作成している中で、MDsveXで使用できるプラグインが期待通りの見た目にならない問題に遭遇していました。

MDsveX で使用できるプラグインといえば、 Remark , Rehype です。

これらのプラグインを、ある条件下で利用するとスタイルがぐちゃぐちゃになってしまいます。

その原因と対策について、紹介していきます。

どういう条件で問題が発生するの?

タイトルのとおりですが、Tailwind CSS で利用できる .prose クラスと、デザインが関わるプラグインを掛け合わせたときに、デザイン崩れが発生します。

◉ 期待するデザイン

expect-link-card

◉ 実際のデザイン

actual-link-card

原因

tailwindcss-typography.prose のCSSと、プラグインで用意(or 推奨)されているCSSが衝突する事によって、スタイル崩れが引き起こされています。

Tailwind CSS の .prose とは?

正式にお伝えすると、“Tailwind CSS の” というより、 tailwindcss-typography.prose クラスの効果になります。 このクラスを付与した要素を良い感じの見た目にしてくれる優れモノです。

GitHub - tailwindlabs/tailwindcss-typography: Beautiful typographic defaults for HTML you don't control.
Beautiful typographic defaults for HTML you don't control. - tailwindlabs/tailwindcss-typography
GitHub - tailwindlabs/tailwindcss-typography: Beautiful typographic defaults for HTML you don't control. favicon github.com
GitHub - tailwindlabs/tailwindcss-typography: Beautiful typographic defaults for HTML you don't control.

Markdown → HTML に変換したあと、細かいスタイルを設定することなく、 .prose を付与するだけで整った見た目を実現してくれます。

MDsveX のプラグイン とは?

MDsveX は、mdsvex.config.js で以下のように指定し、 compile時にオプションとして読み込ませればプラグインが実行されます。

// mdsvex.config.js
import { defineMDSveXConfig as defineConfig } from "mdsvex";
import remarkLinkCard from "remark-link-card";

const config = defineConfig({
  extensions: [".svelte.md", ".md", ".svx"],
  remarkPlugins: [
    // 読み込ませたいプラグインを指定
    [remarkLinkCard, { shortenUrl: true }],
  ],
  rehypePlugins: [],
});

export default config;

この設定をした状態で、更に公式で推奨されるCSSを書きます。

今更の紹介ですが、今回例として挙げているプラグインは RemarkLinkCard という、URLをリンクカードに変換してくれるものです。

公式で推奨されるCSSは以下に記載があります。

GitHub - gladevise/remark-link-card
Contribute to gladevise/remark-link-card development by creating an account on GitHub.
GitHub - gladevise/remark-link-card favicon github.com
GitHub - gladevise/remark-link-card

このスタイルを当てることによって、公式的に期待する見た目を実現してくれます。

この2つが合わさるとどうなるの?

例えばリンクカードだと <a><img> などのタグが必要になるわけですが、このタグに対して既に tailwindcss-typography は CSS を当てています。

.prose :where(a):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
  color: var(--tw-prose-links);
  text-decoration: underline;
  font-weight: 500;
}

.prose :where(img):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
  margin-top: 2em;
  margin-bottom: 2em;
}

そのため、「MDsveXプラグインに対するCSS + .prose のCSS」が適用されてしまい、不要なマージンが加わってしまう等の問題が発生し、スタイル崩れに繋がります。

対策

tailwindcss-typography の仕様になるのですが、もし .prose 以下の要素で用意されたCSSを当てたくない場合、その要素に対して .not-prose というクラスを付与すればCSSを当てないようにすることが出来ます。

確かに、CSSもそのように書かれてますよね

/* :not(:where) を使って、 `.not-prose` を除外している */
.prose :where(img):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
  margin-top: 2em;
  margin-bottom: 2em;
}

まず、MDsveXのプラグインを独自にラップしたものを用意します。

そのラップの中では、生成される要素に対して not-prose というクラスを付与するような処理を記述します。

RemarkLinkCard に対して、僕は以下のように記載しました。

import defaultRemarkLinkCard from "remark-link-card";

const remarkLinkCard = (options) => {
  const basePlugin = defaultRemarkLinkCard(options);

  return async (tree) => {
    // 元々のプラグインの読み込み
    const rlc = await basePlugin(tree);

    for (let node of rlc.children) {
      if (node.type !== "html" || !node.value) {
        continue;
      }

      // 目当ての親要素を特定し、その要素に対して not-prose を付与する
      node.value = node.value.replace("rlc-container", "rlc-container not-prose");
    }
  };
};

export default remarkLinkCard;

これにより、親要素に対して not-prose が付与され、tailwindcss-typography のCSSを当てることなく、純粋にプラグインに対するCSSのみを当てることに成功します。

この記事をシェアする

© 2025 tatsuya-develop