tailwindCSS - 如何在旋转木马幻灯片上添加按钮?

tailwindCSS - How to add a Button on a carousel slide?

我一直在玩这个 Carousel created by Tom Smedley。他使用 AlpineJS 和 TailwindCSS。这真是一个华丽的设计。

我有re-edited上面链接的代码笔来解决我的问题。

Here is my version of the sandbox which replicates the problem

我为每个轮播幻灯片添加了一个 LEARN MORE 按钮,但是该按钮隐藏在 <h1> 内容 header 后面。为了测试,我在按钮上添加了悬停效果来改变颜色,但是按钮不能悬停。

这是我的目标截图:

我不关心按钮是否在幻灯片之外(由于 h1 文本长度),我只希望它位于 header 文本的左下方。

我尝试了很多使用 flex、grids 等的尝试...但我一直在挣扎。谢谢你的帮助。

将所有 <button> 标签放在 <h1> 标签内,并插入以下 CSS:

 h1 > button {
      position: absolute !important;
      left: 0;
      top: 100%;
      font-size: 1rem !important;
    }

我还包含了一个片段。 运行 全屏模式:

function carousel() {
        return {
            active: 0,
            init() {
                var flkty = new Flickity(this.$refs.carousel, {
                    wrapAround: true,
                });
                flkty.on("change", (i) => (this.active = i));
            },
        };
    }

    function carouselFilter() {
        return {
            active: 0,
            changeActive(i) {
                this.active = i;

                this.$nextTick(() => {
                    let flkty = Flickity.data(
                        this.$el.querySelectorAll(".carousel")[i]
                    );
                    flkty.resize();

                    console.log(flkty);
                });
            },
        };
    }
.flickity-viewport {
      height: 500px !important;
    }

    h1 > button {
      position: absolute !important;
      left: 0;
      top: 100%;
      font-size: 1rem !important;
      pointer-events: auto; /* This is part of EDIT 2 */
    }
    
<html>

<head></head>
<script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@1.2.0/dist/tailwind.min.css">

<body>
    <main
      class="min-h-screen bg-black text-white flex items-center justify-center"
      x-data="carouselFilter()"
    >
      <div class="container grid grid-cols-1">
        <div class="flex py-12 justify-center">
          <a
            class="
              px-2
              text-lg
              uppercase
              font-bold
              tracking-widest
              hover:text-white
            "
            :class="{ 'text-gray-800': active != 0 }"
            href="#"
            @click.prevent="changeActive(0)"
            >Lorem Ipsum</a
          >
        </div>

        <div
          class="row-start-2 col-start-1"
          x-show="active == 0"
          x-transition:enter="transition ease-out duration-300"
          x-transition:enter-start="opacity-0 transform scale-90"
          x-transition:enter-end="opacity-100 transform scale-100"
          x-transition:leave="transition ease-in duration-300"
          x-transition:leave-start="opacity-100 transform scale-100"
          x-transition:leave-end="opacity-0 transform scale-90"
        >
          <div
            class="grid grid-cols-1 grid-rows-1"
            x-data="carousel()"
            x-init="init()"
          >
            <div
              class="
                col-start-1
                row-start-1
                relative
                z-20
                flex
                items-center
                justify-center
                pointer-events-none
              "
            >
              <h1
                class="absolute text-5xl uppercase font-black tracking-widest"
                x-show="active == 0"
                x-transition:enter="transition ease-out duration-300"
                x-transition:enter-start="opacity-0 transform translate-y-12"
                x-transition:enter-end="opacity-100 transform translate-y-0"
                x-transition:leave="transition ease-out duration-300"
                x-transition:leave-start="opacity-100 transform translate-y-0"
                x-transition:leave-end="opacity-0 transform -translate-y-12"
              >
                Lorem Ipsum is simply dummy text of the printing and typesetting
                industry. Lorem Ipsum has been the industry's standard dummy
                text ever since the 1500s
                <button
                  class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  "
                  x-show="active == 0"
                >
                  LEARN MORE
                </button>
              </h1>

              <h1
                class="absolute text-5xl uppercase font-black tracking-widest"
                x-show="active == 1"
                x-transition:enter="transition ease-out duration-300"
                x-transition:enter-start="opacity-0 transform translate-y-12"
                x-transition:enter-end="opacity-100 transform translate-y-0"
                x-transition:leave="transition ease-out duration-300"
                x-transition:leave-start="opacity-100 transform translate-y-0"
                x-transition:leave-end="opacity-0 transform -translate-y-12"
              >
                It is a long established fact that a reader will be distracted
                by the readable content of a page when looking at its layout.
                <button
                  class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  "
                  x-show="active == 1"
                >
                  LEARN MORE
                </button>
              </h1>
              <h1
                class="absolute text-5xl uppercase font-black tracking-widest"
                x-show="active == 2"
                x-transition:enter="transition ease-out duration-300"
                x-transition:enter-start="opacity-0 transform translate-y-12"
                x-transition:enter-end="opacity-100 transform translate-y-0"
                x-transition:leave="transition ease-out duration-300"
                x-transition:leave-start="opacity-100 transform translate-y-0"
                x-transition:leave-end="opacity-0 transform -translate-y-12"
              >
                There are many variations of passages of Lorem Ipsum available
                <button
                  class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  "
                  x-show="active == 2"
                >
                  LEARN MORE
                </button>
              </h1>
              <h1
                class="absolute text-5xl uppercase font-black tracking-widest"
                x-show="active == 3"
                x-transition:enter="transition ease-out duration-300"
                x-transition:enter-start="opacity-0 transform translate-y-12"
                x-transition:enter-end="opacity-100 transform translate-y-0"
                x-transition:leave="transition ease-out duration-300"
                x-transition:leave-start="opacity-100 transform translate-y-0"
                x-transition:leave-end="opacity-0 transform -translate-y-12"
              >
                but the majority have suffered alteration in some form
                <button
                  class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  "
                  x-show="active == 3"
                >
                  LEARN MORE
                </button>
              </h1>
            </div>

            <div class="carousel col-start-1 row-start-1" x-ref="carousel">
              <div class="w-3/5 px-2">
                <img
                  src="https://images.unsplash.com/photo-1581375221876-8f287f7cd2cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=770&q=80"
                  loading="lazy"
                />
              </div>
              <div class="w-3/5 px-2">
                <img
                  src="https://images.unsplash.com/photo-1581375279144-bb3b381c7046?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                  loading="lazy"
                />
              </div>
              <div class="w-3/5 px-2">
                <img
                  src="https://images.unsplash.com/photo-1581375303816-4a17124934f7?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                  loading="lazy"
                />
              </div>
              <div class="w-3/5 px-2">
                <img
                  src="https://images.unsplash.com/photo-1494253109108-2e30c049369b?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                  loading="lazy"
                />
              </div>
            </div>
          </div>
        </div>

        <div
          class="row-start-2 col-start-1"
          x-show="active == 1"
          x-transition:enter="transition ease-out duration-300"
          x-transition:enter-start="opacity-0 transform scale-90"
          x-transition:enter-end="opacity-100 transform scale-100"
          x-transition:leave="transition ease-in duration-300"
          x-transition:leave-start="opacity-100 transform scale-100"
          x-transition:leave-end="opacity-0 transform scale-90"
        ></div>
      </div>
    </main>
</body>

</html>

您无法对按钮应用悬停效果的原因是 pointer-events 属性 已设置为 none,在 div 包含 <h1><button> 标签。这是因为如果不这样设置,则应用于背景的拖动功能将不起作用。因此,它是能够单击按钮并突出显示标题文本,还是能够拖动和滚动背景之间的选择。

如果删除 pointer-events-none class,您会注意到悬停效果在按钮上起作用。

编辑:

好的,所以我们进入第 2 部分。基本上我们需要做的是将按钮提升到 headers 所在的级别。当此页面在 [=100= 中呈现时],您可以使用 DevTools 检查元素。我从 DOM 复制了按钮元素,并将它们放在与所有 <h1> 标签相同的容器中。所以现在你有 2 组按钮。这是一组的样子:

<button class="flickity-button flickity-prev-next-button previous custom-flickity-button" type="button" aria-label="Previous" onclick="slide('previous')">
  <svg class="flickity-button-icon" viewBox="0 0 100 100">
    <path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" class="arrow"></path>
  </svg>
</button>
<button class="flickity-button flickity-prev-next-button custom-flickity-button next" type="button" aria-label="Next" onclick="slide('next')">
  <svg class="flickity-button-icon" viewBox="0 0 100 100">
    <path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" class="arrow" transform="translate(100, 100) rotate(180) "></path>
  </svg>
</button>

稍微浏览一下 Flickity 文档,您会发现按钮是 optional,用于渲染。同样,因为我们不会直接与 Flickity 实例交互,所以我在初始化时禁用了拖动功能。这看起来像这样:

function carousel() {
    return {
      active: 0,
      init() {
        var flkty = new Flickity(this.$refs.carousel, {
          wrapAround: true,
          draggable: false, // This is new
          prevNextButtons: false // This is new
        });
        flkty.on("change", (i) => (this.active = i));
      }
    };
  }

由于我们添加的新按钮基本上都是 Flickity 使用的按钮,因此我们真的不需要太担心样式问题。只需要稍作修改。为了减少意外修改实际 CSS 的机会,我添加了 class custom-flickity-button.

附加样式:

  .custom-flickity-button {
    /* 21 is the threshold. Below this, it will be under the h1 text */
    z-index: 25;
  }

  .custom-flickity-button:focus {
    outline: none;
    box-shadow: none;
  }

  /* 
  If you make h1 relative, then this padding will apply. 
  But that was causing some issues while transitioning. 
  I'm leaving this for you to explore. 
  */
  #text-container {
    padding: 0 70px;
  }

最后,我们需要为新按钮提供一些点击功能:

// This is to make the new buttons slide. You can modify the logic to work with multiple carousels, as you've done above
  function slide(value) {
    let flkty = Flickity.data(document.querySelector('.carousel'))
    if (value == 'next') {
      flkty.next()
    } else if (value == 'previous') {
      flkty.previous()
    }
  }

我不太熟悉使用 Alpine 和 Tailwind,因此您可以修改此代码以适应它。但无论如何,这就是你所要求的。带有交互式滑块按钮的交互式 了解更多 按钮。

function carousel() {
        return {
            active: 0,
            init() {
                var flkty = new Flickity(this.$refs.carousel, {
                    wrapAround: true,
                });
                flkty.on("change", (i) => (this.active = i));
            },
        };
    }

    function carouselFilter() {
        return {
            active: 0,
            changeActive(i) {
                this.active = i;

                this.$nextTick(() => {
                    let flkty = Flickity.data(
                        this.$el.querySelectorAll(".carousel")[i]
                    );
                    flkty.resize();

                    console.log(flkty);
                });
            },
        };
    }
    
      // This is to make the new buttons slide. You can modify the logic to work with multiple carousels, as you've done above
  function slide(value) {
    let flkty = Flickity.data(document.querySelector('.carousel'))
    if (value == 'next') {
      flkty.next()
    } else if (value == 'previous') {
      flkty.previous()
    }
  }
.flickity-viewport {
      height: 500px !important;
    }

    h1 > button {
      position: absolute !important;
      left: 0;
      top: 100%;
      font-size: 1rem !important;
    }
    
    .custom-flickity-button {
    /* 21 is the threshold. Below this, it will be under the h1 text */
    z-index: 1
  }

  .custom-flickity-button:focus {
    outline: none;
    box-shadow: none;
    border: none;
  }
      /* 
  If you make h1 relative, then this padding will apply. 
  But that was causing some issues while transitioning. 
  I'm leaving this for you to explore. 
  */
  #text-container {
    padding: 0 70px;
  }
<html>

<head></head>
<script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@1.2.0/dist/tailwind.min.css">

<body>
    <main class="min-h-screen bg-black text-white flex items-center justify-center" x-data="carouselFilter()">
    <div class="container grid grid-cols-1">
      <div class="flex py-12 justify-center">
        <a class="
              px-2
              text-lg
              uppercase
              font-bold
              tracking-widest
              hover:text-white
            " :class="{ 'text-gray-800': active != 0 }" href="#" @click.prevent="changeActive(0)">Lorem Ipsum</a>
      </div>

      <div class="row-start-2 col-start-1" x-show="active == 0" x-transition:enter="transition ease-out duration-300"
        x-transition:enter-start="opacity-0 transform scale-90" x-transition:enter-end="opacity-100 transform scale-100"
        x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 transform scale-100"
        x-transition:leave-end="opacity-0 transform scale-90">
        <div class="grid grid-cols-1 grid-rows-1" x-data="carousel()" x-init="init()">
          <div class="
                col-start-1
                row-start-1
                relative
                z-20
                flex
                items-center
                justify-center
              " id="text-container">
            <button class="flickity-button flickity-prev-next-button previous custom-flickity-button" type="button"
              aria-label="Previous" onclick="slide('previous')"><svg class="flickity-button-icon" viewBox="0 0 100 100">
                <path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" class="arrow"></path>
              </svg></button>
            <button class="flickity-button flickity-prev-next-button custom-flickity-button next" type="button"
              aria-label="Next" onclick="slide('next')"><svg class="flickity-button-icon" viewBox="0 0 100 100">
                <path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" class="arrow"
                  transform="translate(100, 100) rotate(180) "></path>
              </svg></button>
            <h1 class="absolute text-5xl uppercase font-black tracking-widest" x-show="active == 0"
              x-transition:enter="transition ease-out duration-300"
              x-transition:enter-start="opacity-0 transform translate-y-12"
              x-transition:enter-end="opacity-100 transform translate-y-0"
              x-transition:leave="transition ease-out duration-300"
              x-transition:leave-start="opacity-100 transform translate-y-0"
              x-transition:leave-end="opacity-0 transform -translate-y-12">
              Lorem Ipsum is simply dummy text of the printing and typesetting
              industry. Lorem Ipsum has been the industry's standard dummy
              text ever since the 1500s
              <button class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  " x-show="active == 0">
                LEARN MORE
              </button>
            </h1>

            <h1 class="absolute text-5xl uppercase font-black tracking-widest" x-show="active == 1"
              x-transition:enter="transition ease-out duration-300"
              x-transition:enter-start="opacity-0 transform translate-y-12"
              x-transition:enter-end="opacity-100 transform translate-y-0"
              x-transition:leave="transition ease-out duration-300"
              x-transition:leave-start="opacity-100 transform translate-y-0"
              x-transition:leave-end="opacity-0 transform -translate-y-12">
              It is a long established fact that a reader will be distracted
              by the readable content of a page when looking at its layout.
              <button class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  " x-show="active == 1">
                LEARN MORE
              </button>
            </h1>
            <h1 class="absolute text-5xl uppercase font-black tracking-widest" x-show="active == 2"
              x-transition:enter="transition ease-out duration-300"
              x-transition:enter-start="opacity-0 transform translate-y-12"
              x-transition:enter-end="opacity-100 transform translate-y-0"
              x-transition:leave="transition ease-out duration-300"
              x-transition:leave-start="opacity-100 transform translate-y-0"
              x-transition:leave-end="opacity-0 transform -translate-y-12">
              There are many variations of passages of Lorem Ipsum available
              <button class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  " x-show="active == 2">
                LEARN MORE
              </button>
            </h1>
            <h1 class="absolute text-5xl uppercase font-black tracking-widest" x-show="active == 3"
              x-transition:enter="transition ease-out duration-300"
              x-transition:enter-start="opacity-0 transform translate-y-12"
              x-transition:enter-end="opacity-100 transform translate-y-0"
              x-transition:leave="transition ease-out duration-300"
              x-transition:leave-start="opacity-100 transform translate-y-0"
              x-transition:leave-end="opacity-0 transform -translate-y-12">
              but the majority have suffered alteration in some form
              <button class="
                    border border-white
                    text-white
                    rounded-md
                    px-4
                    py-2
                    m-2
                    transition
                    duration-500
                    ease
                    select-none
                    hover:text-white hover:bg-indigo-600
                    focus:outline-none focus:shadow-outline
                  " x-show="active == 3">
                LEARN MORE
              </button>
            </h1>
          </div>

          <div class="carousel col-start-1 row-start-1" x-ref="carousel">
            <div class="w-3/5 px-2">
              <img
                src="https://images.unsplash.com/photo-1581375221876-8f287f7cd2cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=770&q=80"
                loading="lazy" />
            </div>
            <div class="w-3/5 px-2">
              <img
                src="https://images.unsplash.com/photo-1581375279144-bb3b381c7046?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                loading="lazy" />
            </div>
            <div class="w-3/5 px-2">
              <img
                src="https://images.unsplash.com/photo-1581375303816-4a17124934f7?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                loading="lazy" />
            </div>
            <div class="w-3/5 px-2">
              <img
                src="https://images.unsplash.com/photo-1494253109108-2e30c049369b?ixlib=rb-1.2.1&auto=format&fit=crop&w=770&q=80"
                loading="lazy" />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div
    class="row-start-2 col-start-1"
    x-show="active == 1"
    x-transition:enter="transition ease-out duration-300"
    x-transition:enter-start="opacity-0 transform scale-90"
    x-transition:enter-end="opacity-100 transform scale-100"
    x-transition:leave="transition ease-in duration-300"
    x-transition:leave-start="opacity-100 transform scale-100"
    x-transition:leave-end="opacity-0 transform scale-90"
  ></div>
  </main>
</body>

</html>

PS:出于某种原因,.custom-flickity-button:focus 仍在代码段中显示蓝色 box-shadow。它没有正常显示,所以你可能想看看那个。

编辑 2:

嘿!刚刚对 pointer-events 属性 进行了一些阅读,结果发现如果将 pointer-events: none 设置为一个元素,但将 pointer-events: auto 的值赋予其任何 children, parent 元素不会阻止指针事件在 children.

上触发

基本上这意味着我在编辑 1 中所做的一切都是不必要的。您需要做的就是在我原来的答案中的按钮上添加一行 CSS -> pointer-events: auto,您将同时拥有可用的按钮和可拖动的旋转木马!

这个不错!它解决了您的问题,您和我今天都学到了新东西! :P

我已经在我的原始代码段中进行了此更改,因此您可以在那里查看。至于编辑 1,我暂时保留它。其他时间可能会帮助别人,谁知道呢。