使用 CSS3 和 jQuery 创建气泡点提示

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

我需要一些提示工具。在寻找一些灵感时,我无需去更远的地方,我的码头就足够了

灵感来源:来自 OS X 码头的上下文菜单

这就是我最终的结果

查看演示

HTML:保持简洁

链接可以在 HTML 中使用提示工具,无需任何花哨的编码。只需为链接提供一个 title 属性。

<a href="#" title="Hi, I'm a tooltip thingy.">link</a>

然后,当您将鼠标悬停在该链接上 1 或 2 秒时,您将获得黄色框。

几乎所有浏览器中的默认提示工具。

我们不要修改它。我们的 HTML 将与上面显示的完全一样。

问题是,那个黄色框完全无法设置样式。也许有一天,一旦像这样的 Shadow DOM 内容被规范化,它就会成为可能,但今天,在任何浏览器中都不可能。因此,我们将运行一些 JavaScript 代码,该代码将提取该属性并使用相同文本创建 <div>,我们将根据需要定位/隐藏/显示这些 <div>

JavaScript:jQuery 插件

像往常一样,我们将使用 jQuery。这正是将其制成插件的完美类型。您可能希望在您自己选择的任意元素集合上使用此功能,以及将其链接起来,因此插件模式是理想的选择。

调用它将像这样简单:

$("article a[title]").tooltips();

这将使所有恰好位于 <article> 元素内部且具有标题的链接都具有提示功能。您可以根据需要更改该选择器。

我们的插件将执行以下操作:

  1. 循环遍历每个链接。
  2. 为每个链接创建一个(隐藏的)div.tooltip,其内部文本与该链接的 title 属性匹配。
  3. 删除链接的 title 属性(唯一摆脱默认黄色框弹出窗口的方法)。
  4. 当鼠标悬停在链接上时…
  5. 相应地定位提示工具并将其滑动到可见状态。
  6. 当鼠标移出链接时…
  7. 将链接从可见状态滑动出去。

大量代码转储,已添加注释供您欣赏。

// IIFE to ensure safe use of $
(function( $ ) {

  // Create plugin
  $.fn.tooltips = function(el) {

    var $tooltip,
      $body = $('body'),
      $el;

    // Ensure chaining works
    return this.each(function(i, el) {

      $el = $(el).attr("data-tooltip", i);

      // Make DIV and append to page 
      var $tooltip = $('<div class="tooltip" data-tooltip="' + i + '">' + $el.attr('title') + '<div class="arrow"></div></div>').appendTo("body");

      // Position right away, so first appearance is smooth
      var linkPosition = $el.position();

      $tooltip.css({
        top: linkPosition.top - $tooltip.outerHeight() - 13,
        left: linkPosition.left - ($tooltip.width()/2)
      });

      $el
      // Get rid of yellow box popup
      .removeAttr("title")

      // Mouseenter
      .hover(function() {

        $el = $(this);

        $tooltip = $('div[data-tooltip=' + $el.data('tooltip') + ']');

        // Reposition tooltip, in case of page movement e.g. screen resize                        
        var linkPosition = $el.position();

        $tooltip.css({
          top: linkPosition.top - $tooltip.outerHeight() - 13,
          left: linkPosition.left - ($tooltip.width()/2)
        });

        // Adding class handles animation through CSS
        $tooltip.addClass("active");

        // Mouseleave
      }, function() {

        $el = $(this);

        // Temporary class for same-direction fadeout
        $tooltip = $('div[data-tooltip=' + $el.data('tooltip') + ']').addClass("out");

        // Remove all classes
        setTimeout(function() {
          $tooltip.removeClass("active").removeClass("out");
          }, 300);

        });

      });

    }

})(jQuery);

需要注意的两件事:1) 最终演示将使提示工具略微动画化。这里 JavaScript 代码中没有发生任何动画。动画是设计。设计是 CSS。因此,我们在 CSS 中执行所有这些操作。2) 这些提示工具的一个小设计细节是它们以相同的方向滑入和滑出。在 CSS 中,仅通过添加和删除单个类并使用过渡,这实际上是不可能的。当类被删除时,过渡将反向运行,因此将以与进入相同的方向滑出。通过使用 setTimeout,我们可以应用一个临时类,并对其进行动画处理。如果有更优雅的想法,请在下面的评论中告诉我。

语义上的问题?

在文档底部添加 div 感觉很糟糕;感觉不太语义化。它们与它们来自的链接之间没有任何有意义的方式通过 HTML 本身连接。

此外,删除 title 标签也让我不太舒服。我听说它们对可访问性没有太大帮助,但仍然如此。我希望 preventDefault() 可以阻止它显示,但它没有。

关于这些内容有任何想法,请在下面的评论中告诉我。

CSS:数量很重要

请注意,在本文顶部的 OS X 屏幕截图中,背景和边框本身稍微透明。我无法在这里实现这一点。这些东西通常是可能的,但是向下的尖箭头是一个额外的元素,并且边框和背景如何相互连接仅仅是通过重叠,并且在任何透明度下看起来都很糟糕。因此,纯色,无伤大雅。

通常,像我们这里这样的尖箭头可以使用伪元素和 CSS 三角形在没有额外标记或图像的情况下实现。在我们的案例中,我们将使用伪元素,但我们也需要一个真实的元素。真实的元素(JavaScript 在每个提示工具 <div> 中插入的 <span>)充当位置框并进行裁剪。伪元素是实际的指针。一个样式与提示工具完全相同的框,只是旋转了 45 度,并被其父级裁剪掉。这是示意图。

这个东西放在那个东西里面。

所以就这样。

.tooltip, .arrow:after {
  background: black;
  border: 2px solid white;
}

.tooltip {
  pointer-events: none;
  opacity: 0;
  display: inline-block;
  position: absolute;
  padding: 10px 20px;
  color: white;
  border-radius: 20px;
  margin-top: 20px;
  text-align: center;
  font: bold 14px "Helvetica Neue", Sans-Serif;
  font-stretch: condensed;
  text-decoration: none;
  text-transform: uppercase;
  box-shadow: 0 0 7px black;
}
.arrow {
  width: 70px;
  height: 16px;
  overflow: hidden;
  position: absolute;
  left: 50%;
  margin-left: -35px;
  bottom: -16px;
}
.arrow:after {
  content: "";
  position: absolute;
  left: 20px;
  top: -20px;
  width: 25px;
  height: 25px;
  box-shadow: 6px 5px 9px -9px black,
              5px 6px 9px -9px black;
  transform:      rotate(45deg);
}
.tooltip.active {
  opacity: 1;
  margin-top: 5px;
  transition: all 0.2s ease;
}
.tooltip.out {
  opacity: 0;
  margin-top: -20px;
}

请注意,.active 类是执行滑动动画的类,而 .out 类是执行滑动出动画的类。

感谢

感谢 Adrian Adkison 在此过程中提供的一些想法和代码。

关于 Opera 的公平警告

Opera 不支持 CSS 中的 pointer-events,因此整个演示似乎无法正常工作。这是因为提示工具实际上是定位在链接的正上方,只是其不透明度被设置为 0。如果要在 Opera 中修复它,您需要在 JavaScript 中将其文字显示设置为 none/block,或者使用 CSS 将它们从链接上移开足够远的距离,以免妨碍可点击性。如果有人想进行此更改,但希望它在其他方面与本演示完全一样,我愿意更新它。

演示

查看 CodePen 上 Chris Coyier (@chriscoyier) 编写的笔
气泡点提示

CodePen 上。