与 Tailwind CSS 集成

将 rehype-smart-links 与 Tailwind CSS 集成,为不同类型的链接添加精美的样式。本页面展示了多种使用 Tailwind 实现的链接样式效果。

基础样式

使用 Tailwind 的基础样式为链接添加颜色和交互效果:

基础Tailwind样式

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        internalLinkClass: 'text-blue-600 hover:text-blue-800 underline hover:no-underline font-medium',
        externalLinkClass: 'text-purple-600 hover:text-purple-800 underline hover:no-underline font-medium',
        brokenLinkClass: 'text-red-500 hover:text-red-700 line-through hover:no-underline font-medium',
        externalLinkAttributes: {
          target: '_blank',
          rel: 'noopener noreferrer'
        }
      }
    ]]
  }
});

带图标的链接

使用 Tailwind 的 Flex 布局为链接添加图标:

带图标的链接

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        wrapperTemplate: (node, linkType) => {
          let icon;
          
          if (linkType === 'internal') {
            // 内部链接添加箭头图标
            icon = h('svg', {
              class: 'w-4 h-4',
              fill: 'none',
              viewBox: '0 0 24 24',
              stroke: 'currentColor'
            }, [
              h('path', {
                'stroke-linecap': 'round',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                d: 'M9 5l7 7-7 7'
              })
            ]);
            
            // 添加链接样式
            node.properties.className = 'inline-flex items-center gap-1 text-blue-600 hover:text-blue-800';
            node.children.push(icon);
          } 
          else if (linkType === 'external') {
            // 外部链接添加外部链接图标
            icon = h('svg', {
              class: 'w-4 h-4',
              fill: 'none',
              viewBox: '0 0 24 24',
              stroke: 'currentColor'
            }, [
              h('path', {
                'stroke-linecap': 'round',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                d: 'M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14'
              })
            ]);
            
            // 添加链接样式和属性
            node.properties.className = 'inline-flex items-center gap-1 text-purple-600 hover:text-purple-800';
            node.properties.target = '_blank';
            node.properties.rel = 'noopener noreferrer';
            node.children.push(icon);
          } 
          else if (linkType === 'broken') {
            // 断开链接添加警告图标
            icon = h('svg', {
              class: 'w-4 h-4',
              fill: 'none',
              viewBox: '0 0 24 24',
              stroke: 'currentColor'
            }, [
              h('path', {
                'stroke-linecap': 'round',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                d: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z'
              })
            ]);
            
            // 添加链接样式并将图标添加到链接开头
            node.properties.className = 'inline-flex items-center gap-1 text-red-500 hover:text-red-700';
            node.children = [icon, ...node.children];
          }
          
          return node;
        }
      }
    ]]
  }
});

按钮样式链接

使用 Tailwind 创建按钮样式的链接:

按钮样式链接

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        internalLinkClass: 'inline-block px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200',
        externalLinkClass: 'inline-block px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white font-medium rounded-lg transition-colors duration-200',
        brokenLinkClass: 'inline-block px-4 py-2 bg-gray-300 hover:bg-gray-400 text-gray-600 font-medium rounded-lg cursor-not-allowed transition-colors duration-200',
        externalLinkAttributes: {
          target: '_blank',
          rel: 'noopener noreferrer'
        }
      }
    ]]
  }
});

卡片样式链接

创建更复杂的卡片样式链接:

卡片样式链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        wrapperTemplate: (node, linkType, url) => {
          // 设置链接基础样式
          const baseClass = 'block p-6 max-w-sm rounded-lg border shadow-md transition-all duration-200';
          let customClass, title, description;
          
          if (linkType === 'internal') {
            customClass = 'bg-white border-gray-200 hover:shadow-lg hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700';
            title = '内部文档';
            description = '点击访问网站内部文档页面,了解更多详情。';
          } 
          else if (linkType === 'external') {
            customClass = 'bg-white border-gray-200 hover:shadow-lg hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700';
            title = 'GitHub 仓库';
            description = '点击访问我们的 GitHub 仓库,获取源代码和最新更新。';
            
            // 添加外部链接属性
            node.properties.target = '_blank';
            node.properties.rel = 'noopener noreferrer';
          } 
          else if (linkType === 'broken') {
            customClass = 'bg-red-50 border-red-200 dark:bg-gray-800 dark:border-red-700 cursor-not-allowed';
            title = '链接失效';
            description = '此链接指向的页面不存在或已被移除。';
          }
          
          // 设置完整的类名
          node.properties.className = `${baseClass} ${customClass}`;
          
          // 创建标题和描述
          const titleEl = h('h5', {
            class: 'mb-2 text-2xl font-bold tracking-tight ' + 
                  (linkType === 'broken' ? 'text-red-500 dark:text-red-400' : 'text-gray-900 dark:text-white')
          }, title);
          
          const descEl = h('p', {
            class: 'font-normal ' + 
                  (linkType === 'broken' ? 'text-red-700 dark:text-red-300' : 'text-gray-700 dark:text-gray-400')
          }, description);
          
          // 设置链接内容
          node.children = [titleEl, descEl];
          
          return node;
        }
      }
    ]]
  }
});

带过渡动画的链接

使用 Tailwind 添加过渡效果和动画:

带动画的链接

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        wrapperTemplate: (node, linkType) => {
          // 获取原始文本内容
          const originalContent = node.children[0]?.value || '链接';
          
          if (linkType === 'internal') {
            // 创建带有下划线动画的内部链接
            const lineElement = h('span', {
              class: 'absolute bottom-0 left-0 w-0 h-0.5 bg-blue-600 group-hover:w-full transition-all duration-300'
            });
            
            const textElement = h('span', {
              class: 'group-hover:text-blue-800 transition-colors duration-300'
            }, '了解更多');
            
            // 设置链接样式和内容
            node.properties.className = 'relative inline-block text-blue-600 font-medium group';
            node.children = [lineElement, textElement];
          } 
          else if (linkType === 'external') {
            // 创建带有下划线动画和箭头的外部链接
            const lineElement = h('span', {
              class: 'absolute bottom-0 left-0 w-0 h-0.5 bg-purple-600 group-hover:w-full transition-all duration-300'
            });
            
            const textElement = h('span', {
              class: 'group-hover:text-purple-800 transition-colors duration-300'
            }, 'GitHub');
            
            const arrowElement = h('span', {
              class: 'inline-block transform translate-x-0 group-hover:translate-x-1 transition-transform duration-200'
            }, '→');
            
            // 设置链接样式和内容
            node.properties.className = 'relative inline-block text-purple-600 font-medium group';
            node.properties.target = '_blank';
            node.properties.rel = 'noopener noreferrer';
            node.children = [lineElement, textElement, arrowElement];
          } 
          else if (linkType === 'broken') {
            // 创建失效链接样式
            const lineElement = h('span', {
              class: 'absolute bottom-0 left-0 w-full h-0.5 bg-red-500 opacity-50'
            });
            
            const textElement = h('span', {
              class: 'line-through'
            }, '失效链接');
            
            // 设置链接样式和内容
            node.properties.className = 'relative inline-block text-red-500 font-medium';
            node.children = [lineElement, textElement];
          }
          
          return node;
        }
      }
    ]]
  }
});

自适应暗色模式

Tailwind 的暗色模式支持:

暗色模式适配链接

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        internalLinkClass: 'text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline dark:decoration-blue-400 hover:decoration-blue-800 dark:hover:decoration-blue-300 transition-colors duration-200',
        externalLinkClass: 'text-purple-600 dark:text-purple-400 hover:text-purple-800 dark:hover:text-purple-300 underline dark:decoration-purple-400 hover:decoration-purple-800 dark:hover:decoration-purple-300 transition-colors duration-200',
        brokenLinkClass: 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 line-through dark:decoration-red-400 hover:decoration-red-800 dark:hover:decoration-red-300 transition-colors duration-200',
        externalLinkAttributes: {
          target: '_blank',
          rel: 'noopener noreferrer'
        }
      }
    ]]
  }
});

徽章样式链接

徽章效果的链接样式:

徽章样式链接

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        wrapperTemplate: (node, linkType) => {
          // 获取原始内容
          const originalContent = node.children[0]?.value || '链接';
          let badgeText, mainClass, badgeClass;
          
          if (linkType === 'internal') {
            badgeText = '内部';
            mainClass = 'inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full hover:bg-blue-200 dark:bg-blue-900 dark:text-blue-300 dark:hover:bg-blue-800 transition-colors duration-200';
            badgeClass = 'ml-1 bg-blue-500 text-blue-100 text-xs px-2 py-0.5 rounded-full dark:bg-blue-300 dark:text-blue-900';
            node.children = ['文档'];
          } 
          else if (linkType === 'external') {
            badgeText = '外部';
            mainClass = 'inline-flex items-center px-3 py-1 bg-purple-100 text-purple-800 text-sm font-medium rounded-full hover:bg-purple-200 dark:bg-purple-900 dark:text-purple-300 dark:hover:bg-purple-800 transition-colors duration-200';
            badgeClass = 'ml-1 bg-purple-500 text-purple-100 text-xs px-2 py-0.5 rounded-full dark:bg-purple-300 dark:text-purple-900';
            node.children = ['GitHub'];
            
            // 添加外部链接属性
            node.properties.target = '_blank';
            node.properties.rel = 'noopener noreferrer';
          } 
          else if (linkType === 'broken') {
            badgeText = '错误';
            mainClass = 'inline-flex items-center px-3 py-1 bg-red-100 text-red-800 text-sm font-medium rounded-full hover:bg-red-200 dark:bg-red-900 dark:text-red-300 dark:hover:bg-red-800 transition-colors duration-200';
            badgeClass = 'ml-1 bg-red-500 text-red-100 text-xs px-2 py-0.5 rounded-full dark:bg-red-300 dark:text-red-900';
            node.children = ['链接失效'];
          }
          
          // 创建徽章
          const badge = h('span', { class: badgeClass }, badgeText);
          
          // 设置链接属性和内容
          node.properties.className = mainClass;
          node.children.push(badge);
          
          return node;
        }
      }
    ]]
  }
});

综合方案

结合多种 Tailwind 样式和 CSS 属性:

综合样式方案

内部链接

外部链接

断开链接

JS
// astro.config.mjs
import { defineConfig } from 'astro/config';
import rehypeSmartLinks from 'rehype-smart-links';
import { h } from 'hastscript';

export default defineConfig({
  markdown: {
    rehypePlugins: [[
      rehypeSmartLinks, 
      {
        wrapperTemplate: (node, linkType) => {
          // 创建包装容器
          const containerDiv = h('div', {
            class: linkType === 'broken' ? 'relative' : 'relative group'
          });
          
          let linkClass, iconPath, animationClass;
          
          if (linkType === 'internal') {
            linkClass = 'inline-flex items-center py-2 px-4 bg-gradient-to-r from-blue-500 to-blue-700 text-white font-medium rounded-lg hover:from-blue-600 hover:to-blue-800 shadow-md hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200';
            iconPath = 'M9 5l7 7-7 7';
            animationClass = 'absolute -bottom-2 left-0 w-full h-0.5 bg-blue-500 transform origin-left scale-x-0 group-hover:scale-x-100 transition-transform duration-300';
          } 
          else if (linkType === 'external') {
            linkClass = 'inline-flex items-center py-2 px-4 bg-gradient-to-r from-purple-500 to-purple-700 text-white font-medium rounded-lg hover:from-purple-600 hover:to-purple-800 shadow-md hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200';
            iconPath = 'M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14';
            animationClass = 'absolute -bottom-2 left-0 w-full h-0.5 bg-purple-500 transform origin-left scale-x-0 group-hover:scale-x-100 transition-transform duration-300';
            
            // 添加外部链接属性
            node.properties.target = '_blank';
            node.properties.rel = 'noopener noreferrer';
          } 
          else if (linkType === 'broken') {
            linkClass = 'inline-flex items-center py-2 px-4 bg-gray-100 dark:bg-gray-700 text-gray-400 font-medium rounded-lg cursor-not-allowed line-through';
            iconPath = 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z';
          }
          
          // 创建图标
          const icon = h('svg', {
            class: linkType === 'broken' ? 'ml-1 w-4 h-4' : 'ml-1 w-4 h-4 transition-transform group-hover:translate-x-1 duration-200',
            fill: 'none',
            viewBox: '0 0 24 24',
            stroke: 'currentColor'
          }, [
            h('path', {
              'stroke-linecap': 'round',
              'stroke-linejoin': 'round',
              'stroke-width': '2',
              d: iconPath
            })
          ]);
          
          // 设置链接样式和内容
          node.properties.className = linkClass;
          node.children = [
            linkType === 'internal' ? '关于我们' : linkType === 'external' ? 'GitHub' : '链接失效',
            icon
          ];
          
          // 添加动画元素(仅适用于内部和外部链接)
          if (linkType !== 'broken') {
            const animationLine = h('span', { class: animationClass });
            containerDiv.children = [node, animationLine];
          } else {
            containerDiv.children = [node];
          }
          
          return containerDiv;
        }
      }
    ]]
  }
});

下一步

浏览更多示例:

相关链接 Astro Tailwind CSS DaisyUI
资源 GitHub NPM