CSS 转换、绝对定位和 :target 的问题

Problem with CSS transition, absolute positioning, and :target

我正在尝试开发一个单屏、纯 css 网站界面,允许用户点击一系列选项。目标是允许用户自行 select 完成所需的操作(注册、联系表格、加载新页面等)。

我的方法是将几个绝对定位的 div 放在一个相对定位的包装器中,然后结合使用 z-index 和 :target 来获得所需的结果。

我遇到的问题是幻灯片之间的过渡(每张幻灯片显示用户可以做出的两个选择)。在第一个测试中 (A/B Slide Choice Test (Working) 转换通过从左到右滑动 divs 来工作。随后的两个幻灯片绝对定位到 right:100%,然后 right:0 使用 :target

#target2:target {
        right: 0;
    }
    #target3:target {
        right: 0;
    }
    #target1, #target2, #target3 {
        transition: all 0.6s ease-out;
    }
    #target1 {
        z-index:1;
    }
    #target2 {
        z-index:2;
        right: 100%;
    }
    #target3 {
        z-index:3;
        right: 100%;
    }

结果符合预期 - 单击选项 1A 或 1B 时,会发生转换并显示正确的幻灯片。


但是在第二个测试中,A/B Slide Choice Test (not working),随后的两个 divs,幻灯片 2 和 3,绝对定位到 left:100%,然后 left:0 使用:目标

#target2:target {
        left: 0;
    }
    #target3:target {
        left: 0;
    }
    #target1, #target2, #target3 {
        transition: all 0.6s ease-out;
    }
    #target1 {
        z-index:1;
    }
    #target2 {
        z-index:2;
        left: 100%;
    }
    #target3 {
        z-index:3;
        left: 100%;
    }

几件事情正在发生:

点击决定 1A:

据我所知,点击 1A 激活了错误的目标 and/or 幻灯片 2 和 3 都向左移动(幻灯片 2 一直被推到屏幕外的左侧)。然后,如果您单击选项 3A,则过渡正常(向右滑动,再次显示幻灯片 1)

点击决定 1B:

然后,如果您单击选项 2B,则转换正常(幻灯片回到右侧,再次显示幻灯片 1)


我已经使用 top:100% 和 top:0 以及 bottom:100% 和 bottom:0

尝试了这个绝对定位的转换

出现同样的问题:使用绝对定位的 'top' 值有效,而 'bottom' 值会产生不良行为。

我希望能够在任何方向上使用转换,最终目标是 'direction' 将成为 Joomla 模块中的可配置后端参数。除了这个转换问题外,该模块实际上已经编写、安装和工作正常。


我不知道 :target 是否以某种方式破坏了预期的行为,或者我是否对绝对定位的 CSS 值做错了什么,或者两者都有。或者如果我对 Flexbox 的(有限的)理解把事情搞砸了。

如果需要的话,我完全愿意使用不同的方法来获得工作版本中显示的所需行为(理想情况下仅使用 CSS)。

但到目前为止,在我的互联网搜索中,我还没有找到任何代码片段或我试图完成的单屏 A/B 界面的示例。

非常感谢您的帮助!


编辑:我一直在研究价值观,看看我是否能更好地理解正在发生的事情。

        #target2:target {
        left: 100%;
    }
    #target3:target {
        left: 100%;
    }
    #target1, #target2, #target3 {
        transition: all 0.6s ease-out;
    }
    #target1 {
        z-index:1;
    }
    #target2 {
        z-index:2;
        left: 100%;
    }
    #target3 {
        z-index:3;
        left: 100%;
    }

理论上(据我了解),上面的CSS应该没有变化,因为两个值都是left:100%

但实际上点击决策 1A 或 1B 会导致#target2 和#target3 在屏幕上移动(尽管没有过渡)。

然后我将多张幻灯片添加到相对定位的包装中 div,我发现所有幻灯片 ID 都受到影响(#target2、#target3、#target4、#target5 等) .

我的理解是,点击 href="#target2" 应该只会影响#target2:target,但它会影响所有其他幻灯片 ID,让我认为 position:absolute 和 :target 是冲突的不知何故。

(刘海头放在桌子上)

嘿伙计,如果你制作了一个 codepen 或 jsfiddle 会容易得多。这是一个很长的解释,很难理解。抱歉,我没有解决方案,但如果你制作一个 jsfiddle,我会尽我所能帮助你。

您 运行 遇到的问题确实是 position:absolute 和定位冲突。它们冲突的方式是因为浏览器试图滚动到正确的位置,因为您使用的是锚标记。然后位置开始改变,导致你想要显示的元素消失。

因此,要使其真正按您希望的方式工作,您有两个选择:阻止浏览器滚动。例如放弃锚标记以防止浏览器代替您滚动(也许是 JS 的洒水?)。

或者您可以完全专注于滚动,而忽略绝对定位中的位置变化。


CSS唯一解

既然你要求甚至替代品(最好没有 JS),这里使用 CSS 滚动捕捉(CSS Tricks)来完成过渡的繁重工作。您的所有标记都是相同的。

此解决方案的主要部分值得注意:

在这种情况下,html 元素是具有滚动条的元素,因此它需要 scroll-snap-type 和 behavior

html {
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

所有目标都需要是捕捉点:

#target1,
#target2,
#target3 {
  scroll-snap-align: center;
}

这是使它在基本级别上运行的主要两件事,但还有一些其他有趣的添加使其看起来更漂亮。

我们需要在定位时将目标增加到更大的 z-index,以便它们始终位于最前面。

#target2:target,
#target3:target {
  z-index: 5;
}

当目标 1 未被定位时,它需要固定在一个位置,这样它看起来就像在滚动离开时停留在一个位置(不幸的是,我想不出一个好的方法来完成反向操作)。

#target1:not(:target) {
  position: fixed;
  left: 0;
}

在这种情况下,需要特别在 z-index 上进行转换,这样 target2 在转换出屏幕时不会立即进入 target 3 下面

 section:not(:target) {
  transition: z-index 2s ease-out;
}

body,
html {
  width: 100%;
  height: 100%;
  margin: 0;
  font-family: sans-serif;
}

html {
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overflow: hidden;
}

.mainwrap {
  height: 100%;
  position: relative;
}

.flexwrap {
  position: relative;
  display: flex;
  height: 100%;
}

.contentwrap {
  display: flex;
  flex: 1;
}

figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  padding: 0;
  margin: 0;
}

.flexcolumn {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.leftbox,
.rightbox {
  padding: 5%;
}

.leftbox {
  color: #fff;
}

.rightbox {
  color: #574a46;
}

@media screen and (min-width: 993px) {
  .contentwrap {
    flex-direction: row;
  }
  figure {
    flex-direction: column;
  }
  .flexcolumn {
    justify-content: center;
  }
}

@media screen and (max-width: 992px) {
  .contentwrap {
    flex-direction: column;
  }
  figure {
    flex-direction: row;
  }
  .flexcolumn {
    justify-content: center;
  }
}

.drab {
  background-color: #676c27;
}

.orange {
  background-color: #ff9600;
}

.yellow {
  background-color: #ffcc00;
}

.burgundy {
  background-color: #83240f;
}

.lime {
  background-color: #cccc33;
}

.olive {
  background-color: #333300;
}

.navy {
  background-color: #000033;
}

a {
  color: #ffffff;
}

#target2:target,
#target3:target {
  z-index: 5;
}

#target1:not(:target) {
  position: fixed;
  left: 0;
}

 section:not(:target) {
  transition: z-index 2s ease-out;
}

#target1,
#target2,
#target3 {
  scroll-snap-align: center;
}

#target1 {
  z-index: 1;
}

#target2 {
  z-index: 2;
  left: 100%;
}

#target3 {
  z-index: 3;
  left: 100%;
}

.start {
  position: absolute;
  width: 100%;
  height: 100%;
}

.reset {
  position: absolute;
  height: 100%;
  width: 100%;
  overflow: hidden;
  /* left: 0%; */
  z-index: -1;
  /* transform: translateX(100%); */
}
<div id="decisionTree" class="mainwrap">
  <section class="start" id="target1">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox navy">
          <div class="flexcolumn">
            <h3>I am Decision #1a</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target2">CLICK</a>
        </figure>
        <figure id="tree2" class="fadebox rightbox yellow">
          <div class="flexcolumn">
            <h3>I am Decision #1b</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target3">CLICK</a>
        </figure>
      </div>
    </div>
  </section>
  <section class="reset" id="target2">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox olive">
          <div class="flexcolumn">
            <h3>I am Decision #2a</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target1">CLICK</a>
        </figure>
        <figure id="tree2" class="fadebox rightbox orange">
          <div class="flexcolumn">
            <h3>I am Decision #2b</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target1">CLICK</a>
        </figure>
      </div>
    </div>
  </section>
  <section class="reset" id="target3">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox burgundy">
          <div class="flexcolumn">
            <h3>I am Decision #3a</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target1">CLICK</a>
        </figure>
        <figure id="tree2" class="fadebox rightbox lime">
          <div class="flexcolumn">
            <h3>I am Decision #3b</h3>
            <figcaption>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            </figcaption>
          </div>
          <a href="#target1">CLICK</a>
        </figure>
      </div>
    </div>
  </section>
</div>

需要注意的重要一点是,您不会从最小化的结果中得到这种效果,因为它似乎至少需要一定的高度才能工作。因此,您必须 运行 片段然后单击全屏。


基于

JavaScript的解决方案

如前所述,只要解释清楚/足够简单,JS 解决方案就可以:

本例JS如下。对实际作品进行了评论,使它们更容易理解。通常,此解决方案不是使用 :target,而是通过切换元素中的 .selected class 来工作。这样做的主要好处是摆脱锚标签提供的浏览器滚动事件。

function clickHandler(target){
  // Get the element that should be selected
  const elem = document.querySelector(target);
  // There were no elements to be selected
  if(!elem) return;
  // Get the old selected element (if any)
  const prevElem = document.querySelector('.selected');
  if(prevElem){
    // If there was a previously selected element, it isn't anymore
     prevElem.classList.remove('selected'); 
  }
  // Make the new element selected
  elem.classList.add('selected');
}

CSS 变化也很小:

我们使用 .selected

而不是 :target
#target2.selected,
#target3.selected {
  left: 0;
}

我所做的 html 更改是将 a 标签更改为按钮(以便在语义上更正确)并为它们提供 onClick 事件处理程序:

<button onClick="clickHandler('#target3')">CLICK</button>

为了在stack overflow中显示,因为它默认提供了这么短和矮的window,我将min-height设置为390px(所以有一个基本尺寸,以避免来自当它们不合适时,一切都基于 %)

html {
  min-height: 390px;
  overflow-x: hidden;
  overflow-y: auto;
}

function clickHandler(target) {
  // Get the element that should be selected
  const elem = document.querySelector(target);
  // There were no elements to be selected
  if (!elem) return;
  // Get the old selected element (if any)
  const prevElem = document.querySelector('.selected');
  if (prevElem) {
    // If there was a previously selected element, it isn't anymore
    prevElem.classList.remove('selected');
  }
  // Make the new element selected
  elem.classList.add('selected');
}
html {
  min-height: 390px;
  overflow-x: hidden;
  overflow-y: auto;
}

body,
html {
  width: 100%;
  height: 100%;
  margin: 0;
  font-family: sans-serif;
}

.mainwrap {
  height: 100%;
  position: relative;
}

.flexwrap {
  position: relative;
  display: flex;
  height: 100%;
}

.contentwrap {
  display: flex;
  flex: 1;
}

figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  padding: 0;
  margin: 0;
}

.flexcolumn {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.leftbox,
.rightbox {
  padding: 5%;
}

.leftbox {
  color: #fff;
}

.rightbox {
  color: #574a46;
}

@media screen and (min-width: 993px) {
  .contentwrap {
    flex-direction: row;
  }
  figure {
    flex-direction: column;
  }
  .flexcolumn {
    justify-content: center;
  }
}

@media screen and (max-width: 992px) {
  .contentwrap {
    flex-direction: column;
  }
  figure {
    flex-direction: row;
  }
  .flexcolumn {
    justify-content: center;
  }
}

.drab {
  background-color: #676c27;
}

.orange {
  background-color: #ff9600;
}

.yellow {
  background-color: #ffcc00;
}

.burgundy {
  background-color: #83240f;
}

.lime {
  background-color: #cccc33;
}

.olive {
  background-color: #333300;
}

.navy {
  background-color: #000033;
}

a {
  color: #ffffff;
}

#target2.selected,
#target3.selected {
  left: 0;
}

#target1,
#target2,
#target3 {
  transition: all 0.6s ease-out;
}

#target1 {
  z-index: 1;
}

#target2 {
  z-index: 2;
  left: 100%;
}

#target3 {
  z-index: 3;
  left: 100%;
}

.start {
  position: absolute;
  width: 100%;
  height: 100%;
}

.reset {
  position: absolute;
  height: 100%;
  width: 100%;
  overflow: hidden;
}
<div id="decisionTree" class="mainwrap">
  <section class="start" id="target1">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox navy">
          <div class="flexcolumn">
            <h3>I am Decision #1a</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target2')">CLICK</button>
        </figure>
        <figure id="tree2" class="fadebox rightbox yellow">
          <div class="flexcolumn">
            <h3>I am Decision #1b</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target3')">CLICK</button>
        </figure>
      </div>
    </div>
  </section>
  <section class="reset" id="target2">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox olive">
          <div class="flexcolumn">
            <h3>I am Decision #2a</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target1')">CLICK</button>
        </figure>
        <figure id="tree2" class="fadebox rightbox orange">
          <div class="flexcolumn">
            <h3>I am Decision #2b</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target1')">CLICK</button>
        </figure>
      </div>
    </div>
  </section>
  <section class="reset" id="target3">
    <div class="flexwrap">
      <div class="contentwrap">
        <figure id="tree1" class="fadebox leftbox burgundy">
          <div class="flexcolumn">
            <h3>I am Decision #3a</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target1')">CLICK</button>
        </figure>
        <figure id="tree2" class="fadebox rightbox lime">
          <div class="flexcolumn">
            <h3>I am Decision #3b</h3>
            <figcaption>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</figcaption>
          </div>
          <button onClick="clickHandler('#target1')">CLICK</button>
        </figure>
      </div>
    </div>
  </section>
</div>