PAYATHON 2026

如何将方形时钟的刻度线排列到方形边缘?

数据小许

结论

现有刻度线以 transform-origin: 50% 50cqi 为旋转中心,旋转半径固定,所以排列成圆形。要让 60 条刻度线沿正方形边缘分布,需要根据每条刻度的角度计算它与正方形边界的交点,再设置刻度线的位置和旋转角度。

下面的代码从时钟中心出发,计算每条刻度线到正方形边缘的距离,并每隔 5 条设置一条较长的主刻度。

CSS

用以下规则替换原有的 .diallines 和 .diallines:nth-of-type(5n) 定位规则:

.diallines {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  width: 0.67cqi;
  height: 5cqi;
  margin: 0;
  background: #666;
  transform-origin: center;
}

.diallines.major {
  width: 1.33cqi;
  height: 8.33cqi;
}

:nth-of-type(5n) 根据同级元素的标签位置匹配,不能保证选中每第五条 .diallines。这里由 JavaScript 为主刻度添加 .major 类。

JavaScript

替换原先创建刻度线的循环。下面的代码会先移除 HTML 中已有的刻度线,再创建 60 条新刻度线:

var clockEl = document.querySelector('.clock');

clockEl.querySelectorAll('.diallines').forEach(function (line) {
  line.remove();
});

for (var i = 0; i < 60; i++) {
  var angle = i * 6;
  var radians = angle * Math.PI / 180;
  var sin = Math.sin(radians);
  var cos = Math.cos(radians);

  var line = document.createElement('div');
  line.className = i % 5 === 0 ? 'diallines major' : 'diallines';
  clockEl.appendChild(line);

  var tickLength = line.getBoundingClientRect().height;
  var half = Math.min(clockEl.clientWidth, clockEl.clientHeight) / 2;
  var edgeDistance = half / Math.max(Math.abs(sin), Math.abs(cos));
  var radius = edgeDistance - tickLength / 2;

  line.style.left = (clockEl.clientWidth / 2 + sin * radius) + 'px';
  line.style.top = (clockEl.clientHeight / 2 - cos * radius) + 'px';
  line.style.transform =
    'translate(-50%, -50%) rotate(' + angle + 'deg)';
}

Math.max(Math.abs(sin), Math.abs(cos)) 根据方向计算射线到正方形边界的距离。当刻度角度为 45deg、135deg 等时,交点会落在正方形的角上。减去刻度线长度的一半后,刻度线会以交点为中心。若要让刻度线完全位于边缘内侧,可以再从 radius 中减去一小段距离。

让时钟尽可能占满视口

如果“占满”是指尽量利用浏览器视口,同时保持时钟为正方形,可以给 .clock 设置:

.clock {
  width: min(100vw, 100vh);
  height: auto;
  aspect-ratio: 1 / 1;
  box-sizing: border-box;
}

时钟尺寸会根据视口较短的一边确定。若时钟需要适配其他容器,可以将 100vw 和 100vh 换成容器的可用尺寸。

时钟尺寸变化后,需要重新计算刻度位置,例如在窗口尺寸变化时再次运行生成刻度的逻辑。上述代码假设 .clock 是正方形,并且刻度线由这段 JavaScript 重新生成。

备注:内容仅供参考。