【问题标题】:Creating a card flipper with front/back faces WITHOUT absolut positioning创建一个没有绝对定位的正面/背面的卡片翻转器
【发布时间】:2017-02-28 09:11:53
【问题描述】:

我想向我的网站添加一个新功能,该功能使用来自 David Walsh 网站的卡片翻转模式:https://davidwalsh.name/css-flip。问题是,我卡片中的内容是可变的,所以高度是未知的(它也是一个响应式站点)。我的页面底部有一个页脚,需要位于该区域下方,但由于这种方法依赖于绝对定位,因此页脚将位于顶部,就像在这个 codepen 中一样:https://codepen.io/anon/pen/ALJmGZ

任何人都可以想到任何 css hack 或对这种方法的更改,以使卡片不必绝对定位?

HTML:

<div class="flip-container" ontouchstart="this.classList.toggle('hover');">
  <div class="flipper">
    <div class="front">
      <span class="name">David Walsh</span>
    </div>
    <div class="back">
      <div class="back-logo"></div>
      <div class="back-title">@davidwalshblog</div>
      <p>Mozilla Web Developer, MooTools & jQuery Consultant, MooTools Core Developer, Javascript Fanatic, CSS Tinkerer, PHP Hacker, and web lover.</p>
    </div>
  </div>
  <footer>Here is my footer</footer>
</div>

CSS:

.flip-container {
  -webkit-perspective: 1000;
  -moz-perspective: 1000;
  -o-perspective: 1000;
  perspective: 1000;

    border: 1px solid #ccc;
}

    .flip-container:hover .flipper,  
  .flip-container.hover .flipper {
        -webkit-transform: rotateY(180deg);
        -moz-transform: rotateY(180deg);
    -o-transform: rotateY(180deg);
        transform: rotateY(180deg);
    }

.flip-container, .front, .back {
    width: 320px;
    height: 427px;
}

.flipper {
    -webkit-transition: 0.6s;
    -webkit-transform-style: preserve-3d;

    -moz-transition: 0.6s;
    -moz-transform-style: preserve-3d;

  -o-transition: 0.6s;
    -o-transform-style: preserve-3d;

    transition: 0.6s;
    transform-style: preserve-3d;

    position: relative;
}

.front, .back {
    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
  -o-backface-visibility: hidden;
    backface-visibility: hidden;

    position: absolute;
    top: 0;
    left: 0;
}

.front {
    background: url(http://davidwalsh.name/demo/dwflip.jpg) 0 0 no-repeat;
    z-index: 2;
}

.back {
    -webkit-transform: rotateY(180deg);
    -moz-transform: rotateY(180deg);
  -o-transform: rotateY(180deg);
    transform: rotateY(180deg);

    background: #f8f8f8;
}

.front .name {
    font-size: 2em;
    display: inline-block;
    background: rgba(33, 33, 33, 0.9);
    color: #f8f8f8;
    font-family: Courier;
    padding: 5px 10px;
    border-radius: 5px;
    bottom: 60px;
    left: 25%;
    position: absolute;
    text-shadow: 0.1em 0.1em 0.05em #333;

    -webkit-transform: rotate(-20deg);
    -moz-transform: rotate(-20deg);
  -o-transform: rotate(-20deg);
    transform: rotate(-20deg);
}

.back-logo {
    position: absolute;
    top: 40px;
    left: 90px;
    width: 160px;
    height: 117px;
    background: url(http://davidwalsh.name/demo/logo.png) 0 0 no-repeat;
}

.back-title {
    font-weight: bold;
    color: #00304a;
    position: absolute;
    top: 180px;
    left: 0;
    right: 0;
    text-align: center;
    text-shadow: 0.1em 0.1em 0.05em #acd7e5;
    font-family: Courier;
    font-size: 2em;
}

.back p {
    position: absolute;
    bottom: 40px;
    left: 0;
    right: 0;
    text-align: center;
    padding: 0 20px;
  font-family: arial;
  line-height: 2em;
}

footer {
  background:red;
}

【问题讨论】:

  • 您可以将“footer”排除在“flip-container”之外。
  • 这只会起作用,因为该示例中的翻转容器具有明确的高度设置。

标签: html css css-position css-transforms


【解决方案1】:

我还遵循了 David Walsh 博客示例,并且需要在 flex 上下文中执行此操作,因此,我发现翻转面板的绝对定位无法正常工作。

我解决了这个问题

  • .flipper 类中的相对位置
  • 对于 .flipper 类的块也有固定的高度,但为了使用不同的高度模式,假设是高度:15em
  • top: 0 代表前块
  • 顶部:后块的负数

我必须调整值以便在元素之间提供一些边距和空间。 我使用了 onclick 事件而不是悬停,这是我对 UX 的选择。但两者都可以。

<!-- HTML -->
<p>three boxes on a flex basis with a onclick flipper effect</p>
<div class='flexinl'>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 1</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 1</h1>
            </div>
        </div>
    </div>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 2</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 2</h1>
            </div>
        </div>
    </div>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 3</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 3</h1>
            </div>
        </div>
    </div>
</div>  

/* CSS */
.c1 {color:white; background-color:green}
.c2 {color:white; background-color:orange}
.hand { cursor: pointer; }

/* based on David Walsh Flipper */
.flip-container {
    perspective: 1000px;
    border: 1px dashed #a9a9a9;
    margin-bottom:1.5em;    
}
  /* flip the pane when has the backed */
.flip-container.backed .flipper {
    transform: rotateY(180deg);
}
.fli300 {height: 15em;}
.fli300 .front {
    height: 12em !important;
}
.fli300 .back {
    height: 12em !important;
    top: -15em;
}

/* flip speed goes here */
.flipper {
    transition: .4s;
    transform-style: preserve-3d;
    position: relative;    
}

/* hide back of pane during swap */
.flipper .front, .flipper .back {
    backface-visibility: hidden;
    position: relative;
    left: 0;
    height: 100%;
    padding: 1.5em;    
}

/* front pane, placed above back */
.flipper .front {
    z-index: -1;
    top: 0;
    /* for firefox 31 */
    transform: rotateY(0deg);
}

/* back, initially hidden pane */
.flipper .back {
    transform: rotateY(180deg);
}

/* some flex stuff */
.flexinl {  
    display: inline-flex; 
    flex-wrap: wrap;  
    justify-content: flex-start;
}
.flexinl > div {padding:0.2em}

/* some javascript for swapping two classes */

HTMLElement.prototype.swapClasses = function (dosclasses) {
    var clases = dosclasses.split(/\s*\,\s*/);
    var entra = clases[0];
    var sale = clases[1];
    if (this.classList.contains(sale)) {
        this.classList.remove(sale);
        this.classList.add(entra);
    } else {
        this.classList.remove(entra);
        this.classList.add(sale);
    }
    return this;
};

你可以在这个codepen找到它

【讨论】:

    【解决方案2】:

    我今天正在玩这个,只是偶然发现了这个问题,因为我的解决方案带有一个小小的警告。

    .flip-container {
      perspective: 1000;
    }
    .flipper {
      transform-style: preserve-3d;
      display: flex;
      align-items: stretch;
      width: 100%;
      transition: transform 0.6s;
      will-change: transform;
    }
    .flip-container:hover .flipper {
      transform: rotateY(180deg);
    }
    .front, .back {
      width: 100%;
      flex: 0 0 auto;
      backface-visibility: hidden;
    }
    .back {
      transform: rotateY(180deg);
      margin-left: -100%;
    }
    

    这是可行的,因为一行中的弹性项目可以采用最高行项目的高度。根据需要设置.front.back 的样式,只是不要设置它们的高度。

    需要注意的是,如果另一侧在渲染后增长(例如,因为图像已加载),则较短的一侧似乎会出现其渲染高度。如果高度因窗口大小调整而改变,这很好,只是如果内容突然加载似乎不会。当然,这对你来说可能不是这样,但我最终不得不给图像一个具有设定高度的容器。如果您不需要纯 CSS 解决方案,也可以在显示整个翻转卡之前等待图像加载,但这有点题外话,因为您似乎没有使用 img .

    【讨论】:

    • 你救了我的命。这就像一个魅力!结合 absolute + flex + overflow 在 iOS 上不起作用,但这种方法可以!谢谢
    【解决方案3】:

    我找到了一种使用纯 css 并且没有绝对位置的方法来完成此任务。我使用 css 动画而不是过渡,您可以在 50% 关键帧处将元素的高度/宽度设置为 0。查看小提琴:https://codepen.io/anon/pen/bwmkAo

    萨斯:

    @keyframes no-show {
        0% {
            transform: rotateY(0deg);
        height: auto;
        width: 100%;
        }
    
        49% {
            height: auto;
            width: 100%;
        }
    
        50% {
            height: 0;
            width: 0;
        }
    
        100% {
            transform: rotateY(180deg);
            height: 0;
            width: 0;
        }
    }
    
    @keyframes show {
        0% {
            transform: rotateY(-180deg);
            height: 0;
            width: 0;
        }
    
        49% {
            height: 0;
            width: 0;
        }
    
        50% {
            height: auto;
            width: 100%;
        }
    
        100% {
            transform: rotateY(0deg);
            height: auto;
            width: 100%;
        }
    }
    
    .flip-container {
        border: 1px solid #ccc;
    }
    
    .flip-container, .front, .back {
        width: 320px;
    }
    
    .flipper {
        position: relative;
    }
    
    .front, .back {
      position: relative;
        perspective: 1000px;
    
        transform-style: preserve-3d;
        perspective-origin: top center;
        animation-duration: 2s;
        animation-timing-function: linear;
        transition-property: transform;
        animation-fill-mode: forwards;
        -webkit-animation-fill-mode: forwards;
        overflow: hidden;
    }
    
    .front {
        z-index: 2;
    
        transform: rotateY(0deg);
        animation-name: show;
        .flipper.active & {
            animation-name: no-show;
        }
    
      .inner {
        height: 300px;
        background: green;
      }
    }
    
    .back {
        transform: rotateY(-180deg);
        animation-name: no-show;
    
        .flipper.active & {
            animation-name: show;
        }
    
      .inner {
        height: 400px;
        background: blue;
      }
    }
    
    footer {
        background: red;
    }
    

    【讨论】:

      【解决方案4】:

      我认为不使用绝对定位是不可能做出类似这样的效果的。

      做到这一点的最好方法是在 JS 中抢占高度。

      这是一个基本的 CodePen:https://codepen.io/CourtDemone/pen/vXVbGQ

      基本上只是将页脚移出翻转容器并添加一些像这样的JS。

      var heightFront, heightBack;
      
      heightFront = $('.front').height();
      heightBack = $('.back').height();
      
      if(heightFront > heightBack){
        $('.flip-container').height(heightFront);
      }else{
        $('.flip-container').height(heightBack);
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用.front.back 强制容器采用其父级的高度。(height:inherit;)
        JSfiddle:https://jsfiddle.net/9q7xr4ef/

        片段:

        .flip-container {
          -webkit-perspective: 1000;
          -moz-perspective: 1000;
          -o-perspective: 1000;
          perspective: 1000;
          border: 1px solid #ccc;
        }
        .flip-container:hover .flipper,
        .flip-container.hover .flipper {
          -webkit-transform: rotateY(180deg);
          -moz-transform: rotateY(180deg);
          -o-transform: rotateY(180deg);
          transform: rotateY(180deg);
        }
        .flip-container,
        .front,
        .back {
          width: 320px;
          height: 427px;
        }
        .flipper {
          -webkit-transition: 0.6s;
          -webkit-transform-style: preserve-3d;
          -moz-transition: 0.6s;
          -moz-transform-style: preserve-3d;
          -o-transition: 0.6s;
          -o-transform-style: preserve-3d;
          transition: 0.6s;
          transform-style: preserve-3d;
          position: relative;
          height: inherit;
        }
        .front,
        .back {
          -webkit-backface-visibility: hidden;
          -moz-backface-visibility: hidden;
          -o-backface-visibility: hidden;
          backface-visibility: hidden;
          position: absolute;
          top: 0;
          left: 0;
        }
        .front {
          background: url(http://davidwalsh.name/demo/dwflip.jpg) 0 0 no-repeat;
          z-index: 2;
        }
        .back {
          -webkit-transform: rotateY(180deg);
          -moz-transform: rotateY(180deg);
          -o-transform: rotateY(180deg);
          transform: rotateY(180deg);
          background: #f8f8f8;
        }
        .front .name {
          font-size: 2em;
          display: inline-block;
          background: rgba(33, 33, 33, 0.9);
          color: #f8f8f8;
          font-family: Courier;
          padding: 5px 10px;
          border-radius: 5px;
          bottom: 60px;
          left: 25%;
          position: absolute;
          text-shadow: 0.1em 0.1em 0.05em #333;
          -webkit-transform: rotate(-20deg);
          -moz-transform: rotate(-20deg);
          -o-transform: rotate(-20deg);
          transform: rotate(-20deg);
        }
        .back-logo {
          position: absolute;
          top: 40px;
          left: 90px;
          width: 160px;
          height: 117px;
          background: url(http://davidwalsh.name/demo/logo.png) 0 0 no-repeat;
        }
        .back-title {
          font-weight: bold;
          color: #00304a;
          position: absolute;
          top: 180px;
          left: 0;
          right: 0;
          text-align: center;
          text-shadow: 0.1em 0.1em 0.05em #acd7e5;
          font-family: Courier;
          font-size: 2em;
        }
        .back p {
          position: absolute;
          bottom: 40px;
          left: 0;
          right: 0;
          text-align: center;
          padding: 0 20px;
          font-family: arial;
          line-height: 2em;
        }
        footer {
          background: red;
        }
        <div class="flip-container" ontouchstart="this.classList.toggle('hover');">
          <div class="flipper">
            <div class="front">
              <span class="name">David Walsh</span>
            </div>
            <div class="back">
              <div class="back-logo"></div>
              <div class="back-title">@davidwalshblog</div>
              <p>Mozilla Web Developer, MooTools & jQuery Consultant, MooTools Core Developer, Javascript Fanatic, CSS Tinkerer, PHP Hacker, and web lover.</p>
            </div>
          </div>
          <footer>Here is my footer</footer>
        </div>

        #2,一个孩子是相对的:
        JSfiddle:https://jsfiddle.net/9q7xr4ef/2/

        【讨论】:

        • 再一次,我没有在任何地方设置明确的高度,所以这不适用于我的情况。如果没有为翻转容器设置明确的高度,这是行不通的。我的内容是动态的。
        • 这很接近,有点。问题取决于显示的是哪个视图,正面可能更大或背面可能更大。不使用js,这个方法也行不通。
        • 在你给的例子中,正反面是一样的。
        • 再次阅读我最初的帖子。 “问题是,我卡片中的内容是可变的,所以高度是未知的(它也是一个响应式网站)。”
        猜你喜欢
        • 2012-07-21
        • 1970-01-01
        • 2021-02-19
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 2020-10-12
        • 2021-04-26
        • 1970-01-01
        相关资源
        最近更新 更多