css 将图标放入圆圈中

oxalkeyp  于 2023-02-10  发布在  其他
关注(0)|答案(9)|浏览(185)

如何将几个<img>元素放置在一个圆圈中,并使这些元素都成为可单击的链接?我希望它看起来像下面的图片,但我不知道如何实现这种效果。

这可能吗?

qyzbxkaa

qyzbxkaa1#

2020溶液

这是我最近用的一个更现代的解决方案。
我首先从一个图片数组开始生成HTML,不管HTML是用PHP、JS还是HTML预处理器生成的,不管是什么......这都不重要,因为背后的基本思想是一样的。
下面是Pug的代码:

//- start with an array of images, described by url and alt text
- let imgs = [
-   {
-       src: 'image_url.jpg', 
-       alt: 'image alt text'
-   } /* and so on, add more images here */
- ];
- let n_imgs = imgs.length;
- let has_mid = 1; /* 0 if there's no item in the middle, 1 otherwise */
- let m = n_imgs - has_mid; /* how many are ON the circle */
- let tan = Math.tan(Math.PI/m); /* tangent of half the base angle */

.container(style=`--m: ${m}; --tan: ${+tan.toFixed(2)}`)
    - for(let i = 0; i < n_imgs; i++)
        a(href='#' style=i - has_mid >= 0 ? `--i: ${i}` : null)
          img(src=imgs[i].src alt=imgs[i].alt)

生成的HTML如下所示(是的,您也可以手动编写HTML,但之后要进行更改会很痛苦):

<div class="container" style="--m: 8; --tan: 0.41">
  <a href='#'>
    <img src="image_mid.jpg" alt="alt text"/>
  </a>
  <a style="--i: 1">
    <img src="first_img_on_circle.jpg" alt="alt text"/>
  </a>
  <!-- the rest of those placed on the circle -->
</div>

在CSS中,我们决定图片的大小,比如8em--m项位于一个圆上,如果它们位于--m边的多边形的中间,所有边都与圆相切。
如果你很难想象,你可以使用这个interactive demo,它为各种多边形构造内切圆和外切圆,你可以通过拖动滑块来拾取多边形的边数。

这告诉我们容器的大小必须是圆半径的两倍加上图像大小的一半的两倍。
我们还不知道半径,但是如果我们知道边的数目,我们就可以计算出它(因此底角一半的正切值,预先计算并设置为自定义属性--tan)和多边形边。我们可能希望多边形边的大小最小为图像的大小,但我们在边上留下多少是任意的。假设我们在每边都有图像大小的一半,所以多边形的边是图像大小的两倍。这给了我们如下的CSS:

.container {
  --d: 6.5em; /* image size */
  --rel: 1; /* how much extra space we want between images, 1 = one image size */
  --r: calc(.5*(1 + var(--rel))*var(--d)/var(--tan)); /* circle radius */
  --s: calc(2*var(--r) + var(--d)); /* container size */
  position: relative;
  width: var(--s); height: var(--s);
  background: silver /* to show images perfectly fit in container */
}

.container a {
  position: absolute;
  top: 50%; left: 50%;
  margin: calc(-.5*var(--d));
  width: var(--d); height: var(--d);
  --az: calc(var(--i)*1turn/var(--m));
  transform: 
    rotate(var(--az)) 
    translate(var(--r))
    rotate(calc(-1*var(--az)))
}

img { max-width: 100% }

有关变换链如何工作的说明,请参见旧解决方案。
这样,在图像数组中添加或删除图像时,会自动将新数量的图像排列在一个圆圈上,使它们等间距排列,同时调整容器的大小,您可以在this demo中测试这一点。

旧溶液(因历史原因保留)

是的,使用CSS是非常可能的,也是非常简单的。你只需要清楚地记住你想要图片链接的Angular (我在最后添加了一段代码,只是为了在你悬停其中一个时显示Angular )。
你首先需要一个 Package 器,我把它的直径设置为24emwidth: 24em; height: 24em;可以做到这一点),你可以把它设置成任何你想要的,你给它position: relative;
然后,将链接与图像一起水平和垂直地放置在 Package 器的中心,方法是设置position: absolute;top: 50%; left: 50%;margin: -2em;(其中2em是图片链接宽度的一半,我将其设置为4em-同样,您可以将其更改为任何您想要的值,但是在这种情况下不要忘记改变边距)。
然后你决定你想要链接到图片的Angular ,你添加一个类deg{desired_angle}(例如deg0deg45或其他),然后对每个这样的类应用链式CSS转换,如下所示:

.deg{desired_angle} {
   transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}

在这里,您可以将{desired_angle}替换为045等等...
第一个旋转变换旋转对象及其轴,平移变换沿旋转的X轴平移对象,第二个旋转变换将对象带回原位。
这种方法的优点是灵活,你可以在不改变现有结构的情况下,以不同的Angular 添加新的图像。

    • 代码片段**
.circle-container {
        position: relative;
        width: 24em;
        height: 24em;
        padding: 2.8em;
        /*2.8em = 2em*1.4 (2em = half the width of a link with img, 1.4 = sqrt(2))*/
        border: dashed 1px;
        border-radius: 50%;
        margin: 1.75em auto 0;
    }
    .circle-container a {
        display: block;
        position: absolute;
        top: 50%; left: 50%;
        width: 4em; height: 4em;
        margin: -2em;
    }
    .circle-container img { display: block; width: 100%; }
    .deg0 { transform: translate(12em); } /* 12em = half the width of the wrapper */
    .deg45 { transform: rotate(45deg) translate(12em) rotate(-45deg); }
    .deg135 { transform: rotate(135deg) translate(12em) rotate(-135deg); }
    .deg180 { transform: translate(-12em); }
    .deg225 { transform: rotate(225deg) translate(12em) rotate(-225deg); }
    .deg315 { transform: rotate(315deg) translate(12em) rotate(-315deg); }
<div class='circle-container'>
        <a href='#' class='center'><img src='image.jpg'></a>
        <a href='#' class='deg0'><img src='image.jpg'></a>
        <a href='#' class='deg45'><img src='image.jpg'></a>
        <a href='#' class='deg135'><img src='image.jpg'></a>
        <a href='#' class='deg180'><img src='image.jpg'></a>
        <a href='#' class='deg225'><img src='image.jpg'></a>
        <a href='#' class='deg315'><img src='image.jpg'></a>
    </div>

此外,您可以通过使用链接的背景图像而不是使用img标记来进一步简化HTML。

o0lyfsai

o0lyfsai2#

以下是无需绝对定位的简单解决方案:

.container .row {
  margin: 20px;
  text-align: center;
}

.container .row img {
  margin: 0 20px;
}
<div class="container">
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
</div>

http://jsfiddle.net/mD6H6/

azpvetkf

azpvetkf3#

使用@Ana提出的解决方案:

transform: rotate(${angle}deg) translate(${radius}px) rotate(-${angle}deg)

我创建了下面的jsFiddle,它使用纯JavaScript(也有jQuery版本)动态放置圆圈。
它的工作原理相当简单:
x一个一个一个一个x一个一个二个一个x一个一个三个一个

n3schb8v

n3schb8v4#

在@Ana的精彩回答的基础上,我创建了这个动态版本,它允许您在DOM中添加和删除元素,并保持元素之间的比例间距--看看我的小提琴:https://jsfiddle.net/skwidbreth/q59s90oy/

var list = $("#list");

var updateLayout = function(listItems) {
  for (var i = 0; i < listItems.length; i++) {
    var offsetAngle = 360 / listItems.length;
    var rotateAngle = offsetAngle * i;
    $(listItems[i]).css("transform", "rotate(" + rotateAngle + "deg) translate(0, -200px) rotate(-" + rotateAngle + "deg)")
  };
};

$(document).on("click", "#add-item", function() {
  var listItem = $("<li class='list-item'>Things go here<button class='remove-item'>Remove</button></li>");
  list.append(listItem);
  var listItems = $(".list-item");
  updateLayout(listItems);

});

$(document).on("click", ".remove-item", function() {
  $(this).parent().remove();
  var listItems = $(".list-item");
  updateLayout(listItems);
});
#list {
  background-color: blue;
  height: 400px;
  width: 400px;
  border-radius: 50%;
  position: relative;
}

.list-item {
  list-style: none;
  background-color: red;
  height: 50px;
  width: 50px;
  position: absolute;
  top: 50%;
  left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<ul id="list"></ul>
<button id="add-item">Add item</button>
4ktjp1zp

4ktjp1zp5#

这是我在React里做的一个版本,来自这里的例子。
CodeSandbox Example

import React, { useRef, useEffect } from "react";

import "./styles.css";

export default function App() {
  const graph = useRef(null);

  useEffect(() => {
    const ciclegraph = graph.current;
    const circleElements = ciclegraph.childNodes;

    let angle = 360 - 90;
    let dangle = 360 / circleElements.length;

    for (let i = 0; i < circleElements.length; i++) {
      let circle = circleElements[i];
      angle += dangle;
      circle.style.transform = `rotate(${angle}deg) translate(${ciclegraph.clientWidth /
        2}px) rotate(-${angle}deg)`;
    }
  }, []);

  return (
    <div className="App">
      <div className="ciclegraph" ref={graph}>
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
      </div>
    </div>
  );
}
qmelpv7a

qmelpv7a6#

你当然可以用纯css或者JavaScript来做。我的建议是:

  • 如果你已经知道图片数量永远不会改变,那么就计算一下你的风格,然后使用普通的css(优点:性能更佳,非常可靠)
  • 如果这个数字可以在你的应用程序中动态变化,或者只是在未来可能会变化,那么就选择Js解决方案(优点:更经得起未来考验)

我有一个类似的工作要做,所以我创建了一个脚本,并为任何可能需要它的人开源here on Github。它只接受一些配置值,并简单地输出您需要的CSS代码。
如果你想使用Js解决方案,这里有一个简单的指针,它对你很有用。使用这个html作为起点,#box是容器,.dot是图像,/div在中间,你想让所有其他的图像围绕着它:
启动html:

<div id="box">
      <div class="dot"></div>
      <img src="my-img.jpg">
      <!-- all the other images you need-->
    </div>

起始Css:

#box{
      width: 400px;
      height: 400px;
      position: relative;
      border-radius: 100%;
      border: 1px solid teal;
    }

    .dot{
        position: absolute;
        border-radius: 100%;
        width: 40px;
        height: 40px;
        left: 50%;
        top: 50%;
        margin-left: -20px;
        margin-top: -20px;
        background: rebeccapurple;
    }
    img{
      width: 40px;
      height: 40px;
      position: absolute;
    }

可以沿着以下方式创建快速函数:

var circle = document.getElementById('box'),
        imgs = document.getElementsByTagName('img'),
        total = imgs.length,
        coords = {},
        diam, radius1, radius2, imgW;
    
    // get circle diameter
    // getBoundingClientRect outputs the actual px AFTER transform
    //      using getComputedStyle does the job as we want
    diam = parseInt( window.getComputedStyle(circle).getPropertyValue('width') ),
    radius = diam/2,
    imgW = imgs[0].getBoundingClientRect().width,
    // get the dimensions of the inner circle we want the images to align to
    radius2 = radius - imgW
    
    var i,
        alpha = Math.PI / 2,
        len = imgs.length,
        corner = 2 * Math.PI / total;
    
    // loop over the images and assign the correct css props
    for ( i = 0 ; i < total; i++ ){
    
      imgs[i].style.left = parseInt( ( radius - imgW / 2 ) + ( radius2 * Math.cos( alpha ) ) ) + 'px'
      imgs[i].style.top =  parseInt( ( radius - imgW / 2 ) - ( radius2 * Math.sin( alpha ) ) ) + 'px'
    
      alpha = alpha - corner;
    }

您可以看到一个实时示例here

xxslljrj

xxslljrj7#

没有办法用CSS神奇地把可点击的项目放在一个围绕另一个元素的圆圈里。我要做的是用position:relative;的容器。然后用position:absolute;放置所有的元素,用topleft定位它的位置。
即使您没有在标记中放置jquery,最好使用jQuery / javascript。
第一步是使用position:relative;将中心图像完美地放置在容器的中心。

#centerImage {
  position:absolute;
  top:50%;
  left:50%;
  width:200px;
  height:200px;
  margin: -100px 0 0 -100px;
}

之后,你可以用centerImage的offset()减去容器的offset(),把其他元素放在它周围,这样你就得到了图像的topleft

var left = $('#centerImage').offset().left - $('#centerImage').parent().offset().left;
var top = $('#centerImage').offset().top - $('#centerImage').parent().offset().top;

$('#surroundingElement1').css({
  'left': left - 50,
  'top': top - 50 
});

$('#surroundingElement2').css({
  'left': left - 50,
  'top': top 
});

$('#surroundingElement3').css({
  'left': left - 50,
  'top': top + 50 
});

我在这里所做的是将元素relative到centerImage。希望这能有所帮助。

n8ghc7c1

n8ghc7c18#

你可以这样做:fiddle
不要介意定位,这是一个简单的示例

hc2pp10m

hc2pp10m9#

第一步是有6个长柱形框:

第二步是使用position: absolute并将它们全部移到容器的中间:

现在围绕位于bottom center的枢轴点旋转它们。使用:nth-child改变旋转Angular :

div {
    transform-origin: bottom center;
    @for $n from 0 through 7 {
      &:nth-child(#{$n}) {
        rotate: (360deg / 6) * $n;
      }
}

现在你所要做的就是把你的图像放在每一列的远端,然后用一个反旋转来补偿旋转:)
完整来源:
x一个一个一个一个x一个一个二个x
参见CodePen

相关问题