CSS 圓形與橢圓形排版
- February 17, 2023
最近遇到了斜橢圓形 CSS 排版的需求,查詢網路上的文章,做圓形排版或繞圓動畫主要都是用 3D 的方式進行,但我的需求其實是 2D 的,設定的目標是把圓畫出來後,可以很輕易的將物體對圓繞著轉,花了一些時間思考跟測試,最後有了比較簡易的寫法,因此用此邊文章記錄下來。
以下會分別介紹圓形排版、橢圓形排版,以及排版後如何使圓上的物體繞著圓轉做動畫。
圓形排版
圓形排版非常簡單,只需要用 rotate 搭配 translate 即可實現,最後再用 rotate 將內容轉回來
為方便示範將所有內容寫在一起,於開發環境請自行切 component 並以 computed 計算.
1
<template> <div class="circle"> <label for="count"> 輸入個數: <input id="count" min="1" type="number" place="輸入個數" v-model="count" /> </label>
<label for="deg"> 輸入起始角度: <input id="deg" type="number" step="30" place="起始位置" v-model="startDeg" /> </label>
<div class="example-circle"> <div v-for="i in count" :key="i" class="example-circle__item" :style="getStyle(i - 1)" > {{ i }} </div> </div> </div></template>
<script setup lang="ts">import { ref } from "vue";
const count = ref(1);const startDeg = ref(-90);
const getStyle = (index: number) => { const calcDeg = startDeg.value + (index / count.value) * 360;
return { transform: ` rotate(${calcDeg}deg) translate(10rem) rotate(${calcDeg * -1}deg) `, };};</script>
<style lang="scss" scoped>input { border: 1px solid; border-radius: 4px; padding: 4px; margin-bottom: 20px;}
label { display: block; margin-bottom: 24px;}
.example-circle { width: 20rem; height: 20rem; border: 1px solid; border-radius: 50%; margin: 0 auto; position: relative;
&__item { border: 1px solid; width: 4rem; height: 4rem; border-radius: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto;
// for text display: flex; justify-content: center; align-items: center; }}</style>橢圓形排版
橢圓形排版稍微複雜一點,其實就是將圓形壓扁( scaleY(0.5) ),再把元素拉回來( scaleY(2) ),這個倍率可自行調整,壓扁 N (0.5) 倍 就要把元素拉回來 1/N (1/0.5=2) 倍。
1
<template> <div class="ellipse"> <label for="count"> 輸入個數: <input id="count" min="1" type="number" place="輸入個數" v-model="count" /> </label>
<label for="deg"> 輸入起始角度: <input id="deg" type="number" step="30" place="起始位置" v-model="startDeg" /> </label>
<div class="example-ellipse"> <div v-for="i in count" :key="i" class="example-ellipse__item" :style="getStyle(i - 1)" > {{ i }} </div> </div> </div></template>
<script setup lang="ts">import { ref } from "vue";
const count = ref(1);const startDeg = ref(-90);
const getStyle = (index: number) => { const calcDeg = startDeg.value + (index / count.value) * 360;
return { transform: ` rotate(${calcDeg}deg) translate(10rem) rotate(${calcDeg * -1}deg) scaleY(2) `, };};</script>
<style lang="scss" scoped>input { border: 1px solid; border-radius: 4px; padding: 4px; margin-bottom: 20px;}
label { display: block;}
.example-ellipse { width: 20rem; height: 20rem; border: 1px solid; border-radius: 50%; margin: 0 auto; position: relative; transform: scaleY(0.5);
&__item { border: 1px solid; width: 4rem; height: 4rem; border-radius: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto;
// for text display: flex; justify-content: center; align-items: center; }}</style>動畫
這種排法有個好處是當你遇到一個很怪的橢圓形,你只需要對好橢圓形的形狀,靠著修改 rotate 就能確保他繞著圓上跑。
1
<template> <div class="animation-ellipse"> <div class="animation-ellipse__item">1</div> </div></template>
<script setup lang="ts"></script>
<style lang="scss" scope>.animation-ellipse { width: 20rem; height: 20rem; border: 1px solid; border-radius: 50%; margin: 0 auto; position: relative; transform: scaleY(0.5) skewY(35deg);
&__item { border: 1px solid; width: 4rem; height: 4rem; border-radius: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; transform: skewY(-35deg) rotate(-90deg) translate(10rem) rotate(90deg) scaleY(2); animation: 3s round linear infinite;
// for text display: flex; justify-content: center; align-items: center; }
@keyframes round { from { transform: rotate(-90deg) translate(10rem) rotate(90deg) skewY(-35deg) scaleY(2); } to { transform: rotate(270deg) translate(10rem) rotate(-270deg) skewY(-35deg) scaleY(2); } }}</style>