HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URL's added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<!-- ✨ CSS imitates beauty ✨ -->
/*
* 4 February 2022
* CSS No DIV Geometric Blooming Flower 🌻
* inspired by Robin Davey's artwork 👉 tmblr.co/Zm4Rmx2Nv6bXq
* based on the concept of my SVG-in-CSS Flipping Checkerboard 👉 https://codepen.io/ShadowShahriar/pen/podoZKr
* made this CodePen for my best friend ❤
* thank you for all the love and support you have given me since the beginning
*
* recommended view: Full Page
* tested on Firefox v96.0.1/x64, Chrome v97.0.4692.99/x64, Brave v1.31.87/x64, Edge v97.0.1072.76, and Chrome for Android v81.0.4044.138/Android 4.4.2
*
* more info. in the details view
*/
@use 'sass:math';
@use 'sass:color';
// === petal geometry ===
$large-petals-count: 12;
$small-petals-count: 8;
// === colors for petal generation ===
$large-petal-color: #ffcc3b;
$mid-petal-color-1: #ffb534;
$mid-petal-color-2: #ff8f2c;
$small-petal-color: #ffd234;
$petal-root-color: #d06500;
// === as stated in the official documentation (https://sass-lang.com/documentation/breaking-changes/slash-div), using slash (/) as a division operation was deprecated since `Dart Sass v1.33.0` and developers are encouraged to use `math.div` function instead. At present, CodePen offers `Dart Sass 1.32.0`. Hence, I've made a tiny wrapper function for backwards compatibility ===
@function devide($n, $dn) {
// @return math.div($n, $dn);
@return $n / $dn;
}
html {
--zoom: 120;
// === animation configuration ===
--animation-speed: 100; // any value between 1-200. a low value will make the animation slower. values more than 200 will make it look static
--animation-delay: 500ms; // the compiled CSS is over 40KB and requires more computation effort, making the animation glitchy. we add a delay to ensure browsers can process the CSS before the animation begins
--leaf-duration: 1s;
--leafs-start-from: 100deg;
--leaf-1-delay: 500ms;
--leaf-2-delay: 580ms;
--leaf-3-delay: 600ms;
--leaf-timing-func: cubic-bezier(0.18, 0.89, 0.32, 1.28);
--petal-duration: 1s;
--petals-start-from: 50deg;
--petal-1-delay: 0ms;
--petal-2-delay: 100ms;
--petal-3-delay: 200ms;
--petal-timing-func: cubic-bezier(0.68, -0.55, 0.27, 1.55);
// === appearance ===
--color-leaf: hsl(175, 30%, 31%);
--color-leaf-root: hsl(113, 21%, 51%);
--scene-drop-shadow: drop-shadow(11em 17em 27em rgba(0, 0, 0, 0.37));
--petals-offset: 36em;
--petals-large-radius: 204em;
--petals-mid-radius: 136em;
--petals-small-radius: 82em;
filter: var(--scene-drop-shadow);
}
// === converts hex colors to rgb for use in the generated SVG ===
@function rgb-color($color) {
$r: color.red($color);
$g: color.green($color);
$b: color.blue($color);
@return "rgb(#{$r},#{$g},#{$b})";
}
:root {
--unit: 1vmin;
--available-screen-min: 665;
--px: calc(var(--zoom) * (var(--unit) / var(--available-screen-min)));
}
// === quick and dirty reset. also setting the font-size enables us to use em as a responsive unit ===
html,
body,
head {
height: 100%;
position: relative;
padding: 0;
margin: 0;
font-size: calc(1 * var(--px));
background-color: transparent;
}
// === we also need to display <head> as a block element so that we can use its pseudo-elements ===
head {
width: 100%;
position: absolute;
left: 0;
top: 0;
display: block;
}
head::before,
head::after,
body::before,
body::after,
html::before,
html::after {
content: "";
position: absolute;
background-repeat: no-repeat;
// === the following effectively calls the GPU and makes the animation noticeably smoother in Chrome ===
filter: blur(0);
}
// === this returns a polygon clip-path for any possible n-gon (where n = 3, ..., 100) ===
// === percentages are encoded as %25 for use in encoded SVG ===
@function generate-polygon($n) {
$theta: devide(2 * math.$pi, $n);
$point-array: null;
@for $i from 1 through $n {
$a: $theta * $i;
$x: 50% + 50% * math.sin($a);
$y: 50% + 50% * math.cos($a);
$point-array: $point-array, #{$x}25 #{$y}25;
}
@return polygon($point-array);
}
// === this generates n number of divs representing their index in --i CSS variable ===
// === i would like to call them "indexed div"s or idivs ===
@function generate-idivs($n) {
$str: null;
@for $i from 0 to $n {
$str: $str + "%3Cdiv style='--i:#{$i}'%3E%3C/div%3E";
}
@return $str;
}
// === this returns a line tilted to the desired angle ===
@function leaf-root($angle: 130deg) {
@return linear-gradient(
$angle,
#fff0 0,
#fff0 calc(50% - 3em),
var(--color-leaf-root) 50%,
#fff0 calc(50% + 1em),
#fff0 100%
);
}
// === this function places a handful of squares around a circular path. those squares are embedded DOM elements within an SVG container. it returns a background image ===
@function place-petals(
$n,
$size-var,
$ratio-var,
$fill,
$rotate-start: 45deg,
$start: 0.5
) {
$theta: devide(2 * math.$pi, $n);
$shift: $theta * $start;
$layers: null;
@for $i from 1 through $n {
$angle: ($i * $theta) + $shift;
$x: calc(50% + var(#{$ratio-var}) * #{math.cos($angle)});
$y: calc(50% + var(#{$ratio-var}) * #{math.sin($angle)});
$layer-image: url("data:image/svg+xml,\
%3Csvg viewBox='0 0 100 100' width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E\
%3CforeignObject width='100%25' height='100%25'%3E\
%3Cdiv xmlns='http://www.w3.org/1999/xhtml'%3E%3Cdiv class='A'%3E%3C/div%3E%3C/div%3E\
%3Cstyle%3E\
.A{\
position:absolute;left:50px;top:50px;\
width:70px;height:70px;border-radius:8%25;\
transform:translate(-50%25,-50%25) rotate(#{$rotate-start}) rotate(#{$angle}rad);\
background:#{rgb-color($fill)};\
}\
%3C/style%3E%3C/foreignObject%3E%3C/svg%3E");
$this-layer: $layer-image
no-repeat
scroll
$x
$y /
var(#{$size-var})
var(#{$size-var});
$layers: $layers, $this-layer;
}
@return $layers;
}
// === this function creates a camera shutter-like shape by creating a polygon and extending their edges ===
@function create-shutter($n, $size: 25, $thickness: 1, $color: black, $area) {
$grid: 1000;
$multiplier: $grid * 0.01;
$shift: 0.25;
@if $n % 2 == 0 {
$shift: 0.5;
}
$rotate: devide(360, $n) * $shift;
$match: $rotate * -1;
@if $n % 4 == 0 {
$match: 0;
}
@if $n == 3 {
$match: 90;
}
$wrapper: url("data:image/svg+xml,\
%3Csvg viewBox='0 0 #{$grid} #{$grid}' \
width='#{$grid}' height='#{$grid}' \
xmlns='http://www.w3.org/2000/svg'%3E\
%3CforeignObject width='100%' height='100%'%3E\
%3Cdiv xmlns='http://www.w3.org/1999/xhtml'%3E\
%3Cdiv class='c' style='--n:#{$n}'%3E#{generate-idivs($n)}%3C/div%3E\
%3C/div%3E\
%3Cstyle%3E\
.c{\
--r:#{$size * $multiplier}px;\
--j:calc(360 / var(--n));\
--b:calc((var(--j) * 0.5 + 90) * 1deg);\
--s:#{$rotate}deg;\
--c:translate(-50%25,-50%25);\
transform:var(--c) rotate(var(--s));\
width:100%25;height:100%25;\
border-radius:50%25;\
overflow:hidden;\
}\
.c, .c::before, .c div{\
position:absolute;left:50%25;top:50%25;\
}\
.c::before{\
content:'';padding:var(--r);transform:var(--c) rotate(#{$match}deg);\
clip-path:#{generate-polygon($n)};\
}\
.c div{\
--a:calc(var(--j) * var(--i) * 1deg);\
width:#{$grid}px;height:#{$thickness * $multiplier}px;\
transform:var(--c) rotate(var(--a)) translate(calc(var(--r) * -1)) rotate(var(--b)) var(--c);\
}\
.c::before, .c div{\
background:#{rgb-color($color)};\
}\
%3C/style%3E\
%3C/foreignObject%3E\
%3C/svg%3E");
@return $wrapper no-repeat scroll center center / #{$area} #{$area};
}
// =============
// === LEAFS ===
// =============
head::before,
head::after,
html::before {
transform-origin: right top; // === we want to animate their position from the top-right corner ===
background-size: 100% 100%;
background-color: var(--color-leaf);
box-shadow: inset 0 0 12em 10em var(--color-leaf);
}
head::before {
left: calc(50% - 65em);
top: calc(50% + 109em);
transform: translate(-50%, -50%) scale(0) rotate(var(--leafs-start-from))
rotate(80deg) skewX(6deg) skewY(-30deg);
width: 83em;
height: 128em;
border-radius: 50% 9% 32% 4%;
background-image: leaf-root(2deg), leaf-root(2deg), leaf-root(2deg),
leaf-root(92deg), leaf-root(92deg), leaf-root(92deg), leaf-root();
background-position: -56em 30em, -34em 3em, -14em -22em, -16em 96em, 6em 68em,
27em 43em, 0 15em;
}
head::after {
left: calc(50% - 94em);
top: calc(50% + 98em);
transform: translate(-50%, -50%) scale(0) rotate(var(--leafs-start-from))
rotate(-44deg) skewY(-30deg);
width: 83em;
height: 96em;
border-radius: 25% 9% 32% 4%;
background-image: leaf-root(-93deg), leaf-root(-93deg), leaf-root(-93deg),
leaf-root(-1deg), leaf-root(-1deg), leaf-root(-1deg), leaf-root();
background-position: -12em 64em, 7em 41em, 28em 16em, -56em 16em, -36em -8em,
-15em -32em, 0 0;
}
html::before {
left: calc(50% - 120em);
top: calc(50% + 123em);
transform: translate(-50%, -50%) scale(0) rotate(var(--leafs-start-from))
skewX(-15deg) skewY(-18deg);
width: 113em;
height: 121em;
border-radius: 24% 9% 27% 7%;
background-image: leaf-root(-90deg), leaf-root(-90deg), leaf-root(-90deg),
leaf-root(2deg), leaf-root(1deg), leaf-root(0deg), leaf-root(133deg);
background-position: -19em 79em, 9em 50.4em, 35em 21.4em, -21em -41.6em,
-49em -11em, -74em 18em, 0 0;
}
// =============
// === PETALS ===
// =============
body::before,
body::after,
html::after {
transform: translate(-50%, -50%) rotate(var(--petals-start-from)) scale(0);
left: calc(50% + var(--petals-offset));
top: calc(50% - var(--petals-offset));
}
body::before {
padding: var(--petals-large-radius);
--pointer-size: 73em;
--pointer-ratio: 46%;
--hand-size: 104em;
--hand-ratio: 39.3%;
--fill-size: 220em;
--shine-size: 325em;
--shine-color: rgba(255, 255, 255, 0.29);
--fill: linear-gradient(#{$large-petal-color} 0 0) no-repeat scroll 50% 50% /
var(--fill-size) var(--fill-size);
--shine: radial-gradient(
circle at center,
var(--shine-color) 50%,
transparent 72%
)
no-repeat 50% 50% / var(--shine-size) var(--shine-size);
filter: drop-shadow(-25em 10em 7em rgba(254, 136, 10, 0.1));
background: var(--shine), var(--fill),
place-petals(
$large-petals-count,
"--hand-size",
"--hand-ratio",
$large-petal-color,
0,
0.5
),
place-petals(
$large-petals-count,
"--pointer-size",
"--pointer-ratio",
$large-petal-color
);
}
body::after {
padding: var(--petals-mid-radius);
--pointer-size: 56em;
--pointer-ratio: 49%;
--hand-size: 77em;
--hand-ratio: 40.3%;
--fill-size: 107em;
--fill: linear-gradient(#{$mid-petal-color-2} 0 0) no-repeat 50% 50% /
var(--fill-size) var(--fill-size);
background: var(--fill),
place-petals(
$large-petals-count,
"--pointer-size",
"--pointer-ratio",
$mid-petal-color-1,
45deg,
0
),
place-petals(
$large-petals-count,
"--hand-size",
"--hand-ratio",
$mid-petal-color-2,
0,
0
);
}
html::after {
padding: var(--petals-small-radius);
--pointer-size: 39em;
--pointer-ratio: 48.2%;
--hand-size: 54em;
--hand-ratio: 39.4%;
--fill-size: 49em;
--shine-size: 130em;
--circle-1-size: 100em;
--shutter-size: 70em;
--fill: linear-gradient(#{$mid-petal-color-2} 0 0) no-repeat 50% 50% /
var(--fill-size) var(--fill-size);
--shine: radial-gradient(
circle at center,
#{$mid-petal-color-2} 42%,
transparent 72%
)
no-repeat 50% 50% / var(--shine-size) var(--shine-size);
--circle-1: radial-gradient(
circle at center,
#{$small-petal-color} 48%,
transparent 50%
)
no-repeat 50% 50% / var(--circle-1-size) var(--circle-1-size);
background: create-shutter(10, 20, 1, $petal-root-color, var(--shutter-size)),
var(--circle-1), var(--shine), var(--fill),
place-petals(
$small-petals-count,
"--hand-size",
"--hand-ratio",
$small-petal-color,
0,
0
),
place-petals(
$small-petals-count,
"--pointer-size",
"--pointer-ratio",
$small-petal-color,
45deg,
0
);
}
// === keyframes and animation ===
html {
--ams: calc(100 / var(--animation-speed));
}
body::before,
body::after,
html::after {
animation: bloom var(--petal-timing-func)
calc(var(--petal-duration) * var(--ams)) forwards;
}
body::before {
animation-delay: calc(
(var(--animation-delay) + var(--petal-1-delay)) * var(--ams)
);
}
body::after {
animation-delay: calc(
(var(--animation-delay) + var(--petal-2-delay)) * var(--ams)
);
}
html::after {
animation-delay: calc(
(var(--animation-delay) + var(--petal-3-delay)) * var(--ams)
);
}
@keyframes bloom {
to {
transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
}
head::before,
head::after,
html::before {
animation: var(--leaf-timing-func) calc(var(--leaf-duration) * var(--ams))
forwards;
}
head::before {
animation-name: leaf1;
animation-delay: calc(
(var(--animation-delay) + var(--leaf-1-delay)) * var(--ams)
);
}
head::after {
animation-name: leaf2;
animation-delay: calc(
(var(--animation-delay) + var(--leaf-2-delay)) * var(--ams)
);
}
html::before {
animation-name: leaf3;
animation-delay: calc(
(var(--animation-delay) + var(--leaf-3-delay)) * var(--ams)
);
}
@keyframes leaf1 {
to {
transform: translate(-50%, -50%) scale(1) rotate(0deg) rotate(80deg)
skewX(6deg) skewY(-30deg);
}
}
@keyframes leaf2 {
to {
transform: translate(-50%, -50%) scale(1) rotate(0deg) rotate(-44deg)
skewY(-30deg);
}
}
@keyframes leaf3 {
to {
transform: translate(-50%, -50%) scale(1) rotate(0deg) skewX(-15deg)
skewY(-18deg);
}
}
Also see: Tab Triggers