【问题标题】:Wrap icons around an extendable circle将图标环绕在可扩展的圆圈周围
【发布时间】:2015-08-27 06:53:37
【问题描述】:

我有一张可以改变大小的光盘,并在该光盘周围排列了一些图标。图标应始终位于光盘的边缘,并且每个图标之间的间隔应始终保持不变。

这是否可以在纯 css 中完成,而不必在光盘增大或缩小时计算每个图标的位置?

预期结果:

.container:nth-child(1)
{
    position: absolute;
    top: 20px;
    left: 30px;
    height: 280px;
    width: 280px;
}

.container:nth-child(2)
{
    position: absolute;
    top: 20px;
    right: 30px;
    height: 200px;
    width: 200px;
}

.container > *
{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.circle
{
    height: 90%;
    width: 90%;
    border-radius: 50%;
    border: 1px solid blue;
    z-index: 20;
}

.icons
{
    height: 100%;
    width: 100%;
    border: 1px dashed gray;
    box-sizing: border-box;
    z-index: 10;
}

.icons > *
{
    position: absolute;
    top: 50%;
    left: 50%;
    height: 20px;
    width: 20px;
    margin-top: -10px;
    margin-left: -10px;
    border: 1px solid red;
}


.container:nth-child(1) span:nth-child(1)
{
    transform: rotate(230deg) translate(150px) rotate(-230deg);
}

.container:nth-child(1) span:nth-child(2)
{
    transform: rotate(217deg) translate(150px) rotate(-217deg);
}

.container:nth-child(1) span:nth-child(3)
{
    transform: rotate(204deg) translate(150px) rotate(-204deg);
}

.container:nth-child(1) span:nth-child(4)
{
    transform: rotate(191deg) translate(150px) rotate(-191deg);
}


.container:nth-child(2) span:nth-child(1)
{
    transform: rotate(230deg) translate(110px) rotate(-230deg);
}

.container:nth-child(2) span:nth-child(2)
{
    transform: rotate(212deg) translate(110px) rotate(-212deg);
}

.container:nth-child(2) span:nth-child(3)
{
    transform: rotate(194deg) translate(110px) rotate(-194deg);
}

.container:nth-child(2) span:nth-child(4)
{
    transform: rotate(176deg) translate(110px) rotate(-176deg);
}
<div class="container">
    <div class="circle"></div>
    <div class="icons">
        <span>A</span>
        <span>B</span>
        <span>C</span>
        <span>D</span>
    </div>
</div>

<div class="container">
    <div class="circle"></div>
    <div class="icons">
        <span>A</span>
        <span>B</span>
        <span>C</span>
        <span>D</span>
    </div>
</div>

【问题讨论】:

    标签: html css css-shapes css-transforms


    【解决方案1】:

    有一种方法可以通过编程方式完成,但只能使用 CSS3。你需要做的是在它里面有一个元素,它占据整个宽度并且可以旋转,然后反向旋转这些旋转元素的内部容器。

    因此您必须使用:nth-child 来定义圆圈。为了达到正确的效果而不是两次应用样式,我们必须从最后一个元素开始倒计时,以便只吸引某个位置的元素。这是因为:nth-child(2n) 也适用于:nth-child(4n),这可能会创建重叠样式。如果这看起来有点太复杂,请跳到 sn-p - 它实际上非常简单。

    所以你的基本 HTML 将是:

    <wrapper> <!-- This is your disc -->
        <rotation> <!-- A rotation element. -->
           <counter> <!-- A counter-rotation element. This contains your content. -->
    

    第一个元素必须启用位置。第二个元素需要与所有其他次要元素重叠,所以它需要一个绝对位置,而第三个元素,嗯,这取决于你。它只是在那里再次反向旋转它。

    这是一个实现:

    /*The following animation shows that the outer frame is resizeable.*/
    @-webkit-keyframes sizeBounce { 0% {width: 50vw; height: 50vw; }  50% {width: 20vw; height: 20vw; } 100% {width: 50vw; height: 50vw; }}
    @keyframes sizeBounce { 0% {width: 50vw; height: 50vw; }  50% {width: 20vw; height: 20vw; } 100% {width: 50vw; height: 50vw; }}
    
    div {
      position: relative;
      /* Any height you want here */
      width: 20vw;
      height: 20vw;
      border-radius: 50%;
      border: 1px solid #000;
    
      -webkit-animation: sizeBounce 2s infinite;
      animation: sizeBounce 2s infinite;
      
      /* You can do anything you want with this circle! */
      position: absolute;
      top: 50%;
      left: 50%;
      -webkit-transform: translate(-50%,-50%);
      transform: translate(-50%,-50%);
    }
    
    div > span {
      position: absolute;
      display: block;
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      transform: rotateZ(0deg);
      transform-origin: 50% 50%;
    }
    
    div > span > em {
      display: block;
      position: absolute;
      left: 0;
      top: 0;
      width: 20%;
      height: 20%;
      border-radius: 50%;
      border: 1px solid #dd0300;
      text-align: center;
    }
    
    div > span:nth-child(6n-6) {
      -webkit-transform: rotateZ(0deg);
      transform: rotateZ(0deg);
    }
    div > span:nth-child(6n-6) > em {
      -webkit-transform: rotateZ(0deg);
      transform: rotateZ(0deg);
    }
    
    div > span:nth-child(6n-4) {
      -webkit-transform: rotateZ(60deg);
      transform: rotateZ(60deg);
    }
    div > span:nth-child(6n-4) > em {
      -webkit-transform: rotateZ(-60deg);
      transform: rotateZ(-60deg);
    }
    
    div > span:nth-child(6n-3) {
      -webkit-transform: rotateZ(120deg);
      transform: rotateZ(120deg);
    }
    div > span:nth-child(6n-3) > em {
      -webkit-transform: rotateZ(-120deg);
      transform: rotateZ(-120deg);
    }
    
    div > span:nth-child(6n-2) {
      -webkit-transform: rotateZ(180deg);
      transform: rotateZ(180deg);
    }
    div > span:nth-child(6n-2) > em {
      -webkit-transform: rotateZ(-180deg);
      transform: rotateZ(-180deg);
    }
    
    div > span:nth-child(6n-1) {
      -webkit-transform: rotateZ(240deg);
      transform: rotateZ(240deg);
    }
    div > span:nth-child(6n-1) > em {
      -webkit-transform: rotateZ(-240deg);
      transform: rotateZ(-240deg);
    }
      
    div > span:nth-child(6n) {
      -webkit-transform: rotateZ(300deg);
      transform: rotateZ(300deg);
    }
    div > span:nth-child(6n) > em {
      -webkit-transform: rotateZ(-300deg);
      transform: rotateZ(-300deg);
    }
    <div>
      <span><em>1</em></span>
      <span><em>2</em></span>
      <span><em>3</em></span>
      <span><em>4</em></span>
      <span><em>5</em></span>
      <span><em>6</em></span>
    </div>

    还有一种自动化的方法是 SASS,它看起来像这样:

    @mixin rotatePiecemeally($pieces:6,$wrapper:span,$container:em){
        /* First calculate the angle between each piece */
        $degrees : 360 / $pieces;
        /* We want to count back from the amount of pieces to 0
         * The counting is because simple counting 2n, 3n, 4n, ... 
         * will result in 4n inheriting from 2n - to keep things clean,
         * we want to avoid that.  */
        @for $i from 0 through ($pieces - 1){
            & #{$wrapper}:nth-child(#{$pieces}n-#{$i}){
                transform: rotateZ(#{$i * $degrees}deg);
            }
            & #{$wrapper}:nth-child(#{$pieces}n-#{$i}) > #{$container}{
                transform: rotateZ(#{-$i * $degrees}deg);
            }
        }
    }
    

    您可以通过以下方式调用它:

    #mycircle {
        @include rotatePiecemeally(6);
    }
    

    您可以选择包含要用作子元素的元素。不要忘记他们都需要一些绝对定位才能工作。不要忘记添加您需要的任何prefixes(我将它们添加到sn-p,因为我使用的是Safari)

    【讨论】:

    • 据我所知,SASS 是一个 CSS 编译器,任何浏览器本身都不支持。每当圆的大小发生变化时,SASS 会计算运行中的位置吗?因为那是我目前在 JavaScript 中所做的,但我正在寻找 CSS/CSS3 唯一的替代方案。
    • 你不能这样做,因为 CSS 本身永远不知道孩子的数量。但是,您可以使用 SASS 输出一大堆这些,使用样式表,然后通过更改类来触发它们。我以前做过,你得到了完全 CSS 的增强。
    • CSS 还考虑到外圈可以改变,所以只要你在里面保留相同数量的元素,它就应该像魅力一样工作。我将添加一个小动画来说明我的意思:)
    • @notyourtype 我添加了一个动画来缩放外圆。它只是表明外圈可以是您想要的任何正方形大小,这将起作用。
    • 一种有趣的方法,但是圆圈可以采用任何所需的大小,这样就会有大量的类可供选择。
    【解决方案2】:

    如果没有预处理器,我相信您需要一个脚本来实现这一点。在这里,我使用 jQuery 来计算悬停时的间隔。

    注意

    这也将支持动态数量的.circle 元素

    + function() {
      var to;
      $(".wrap").on('mouseenter', function() {
        var circles = $(this).find(".circle");
        var degree = (2 * Math.PI) / circles.length; //calc delta angle
        var transforms = [];
    
        // Calculate the position for each circle
        circles.each(function(index) {
          var x = 100 * Math.cos(-0.5 * Math.PI + degree * (-1 * index - 0.5));
          var y = 100 * Math.sin(-0.5 * Math.PI + degree * (-1 * index - 0.5));
    
          transforms.push('translate(' + x + 'px,' + y + 'px)');
        });
    
        // Function to moves all the circles
        // We'll pop a circle each time and than call this function recursively
        function moveCircles() {
          var transform = transforms.shift();
          circles.css('transform', transform);
    
          circles.splice(0, 1);
          if (circles.length) to = setTimeout(moveCircles, 400);
        }
    
        moveCircles();
      });
    
      $(".wrap").on('mouseleave', function() {
        var circles = $(this).children().css('transform', '');
        clearTimeout(to);
      });
    }();
    html {
      height: 100%;
      background: radial-gradient(ellipse at center, rgba(79, 79, 79, 1) 0%, rgba(34, 34, 34, 1) 100%);
    }
    .wrap {
      height: 300px;
      width: 300px;
      position: relative;
      transform-origin: center center;
      transition: all 0.8s;
    }
    .circle {
      transition: all 0.8s;
      position: absolute;
      height: 5px;
      width: 5px;
      text-align: center;
      line-height: 15px;
      top: calc(50% - 2px);
      left: calc(50% - 2px);
      border-radius: 50%;
      overflow: hidden;
    }
    .parent {
      transition: all 0.8s;
      position: absolute;
      background: gray;
      height: 50px;
      width: 50px;
      text-align: center;
      line-height: 25px;
      top: calc(50% - 25px);
      left: calc(50% - 25px);
      border-radius: 50%;
      z-index: 8;
      box-shadow: inset 2px 2px 10px black, inset 0 0 15px black, 0 0 15px black;
    }
    .parent:before,
    .parent:after {
      content: "";
      position: absolute;
      transition: all 0.8s;
      height: 5px;
      width: 25px;
      top: 22px;
      left: 12px;
      background: black;
      opacity: 1;
    }
    .parent:before {
      top: 15px;
      box-shadow: 0 14px 0 black;
    }
    .parent:hover:before,
    .parent:hover:after {
      transform: translate(0, 20px);
      color: gray;
      opacity: 0;
      box-shadow: 0 14px 0 none;
    }
    .wrap:hover .parent,
    .wrap:hover .parent:before,
    .wrap:hover .parent:after {
      background: darkgray;
    }
    .wrap:hover .parent:before {
      box-shadow: none;
    }
    .wrap:hover .circle {
      height: 50px;
      width: 50px;
      line-height: 25px;
      top: calc(50% - 25px);
      left: calc(50% - 25px);
      box-shadow: inset 2px 2px 10px black, inset 0 0 15px black, 0 0 15px black;
    }
    .circle img {
      position: absolute;
      height: 100%;
      width: 100%;
      left: 0;
      top: 0;
    }
    .circle:before {
      border-radius: 50%;
      transition: all 0.8s;
      content: "";
      position: absolute;
      height: 100%;
      width: 100%;
      top: 0;
      left: 0;
      z-index: 8;
    }
    .circle:after,
    button:after {
      transition: all 0.8s;
      border-radius: 50%;
      content: "";
      position: absolute;
      height: 200%;
      width: 200%;
      top: 50%;
      left: 200%;
      z-index: 8;
      background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 100%);
      background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(50%, rgba(255, 255, 255, 0.4)), color-stop(100%, rgba(255, 255, 255, 0)));
      background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 100%);
      background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 100%);
      background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 100%);
      background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 100%);
      filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#00ffffff', endColorstr='#00ffffff', GradientType=1);
    }
    .circle:hover:after,
    button:hover:after {
      left: -200%;
      top: -50%;
    }
    .circle:hover:before {
      box-shadow: inset 2px 2px 10px black, inset 0 0 15px black, 0 0 15px black;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="wrap">
      <div class="parent"></div>
      <div class="circle">
        <img src="http://lorempixel.com/300/300" />
      </div>
      <div class="circle">
        <img src="http://placekitten.com/g/200/300" />
      </div>
      <div class="circle">
        <img src="http://cdn.flaticon.com/png/256/56729.png" />
      </div>
      <div class="circle">
        <img src="http://cdn.flaticon.com/png/256/54976.png" />
      </div>
      <div class="circle">Just Text</div>
      <div class="circle">
        <img src="http://cdn.flaticon.com/png/256/56582.png" />
      </div>
    </div>

    【讨论】:

    • 感谢您的回答,我已经在 J​​avaScript 中有类似的东西,但我想知道是否可以仅在 CSS 中执行此操作。此外,我的意图不是安排所有图标来填充圆圈周围的空间,而是将它们放在一起并适合圆圈的边界,正如我在原始 sn-p 中所说明的那样。
    • @notyourtype:CSS 不是为此而设计的。它是为造型而设计的,这肯定更多地属于事物的操纵方面。当然,它可以在 CSS 中完成,但与 js 解决方案相比,它会更慢、效率更低且编写时间更长。
    猜你喜欢
    • 2021-07-30
    • 2021-06-24
    • 2011-10-13
    • 2021-05-29
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    相关资源
    最近更新 更多