在可扩展的圆圈周围包裹图标

时间:2015-06-11 14:05:54

标签: html css css3 css-shapes css-transforms

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

这可以在纯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>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

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

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

所以你的基本HTML将是:

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

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

继承人的实施:

&#13;
&#13;
/*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);
}
&#13;
<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>
&#13;
&#13;
&#13;

有一种自动化方法是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(我将它们添加到代码段中,因为我使用的是Safari)

答案 1 :(得分: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>