<h1>CSS Transform</h1>
<div class="controls"><button class="reset">Toggle transformations</button></div>
<div class="container">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/9729/dad01.png" id="no1" />
</div>
<svg width="100%" height="100%" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path id="_scale" d="M57.912,75l17.088,0l0,-17.088m-50,-15.824l0,-17.088l17.088,0" style="fill:none;stroke:white;stroke-width:2px;"/>
<path id="_perspective" d="M25,65.492l15.135,-29.411l19.73,0l15.135,29.411l-50,0Z" style="fill:none;stroke:white;stroke-width:2px;"/>
<g id="_rotate">
<path d="M68.752,50c0,10.349 -8.403,18.752 -18.752,18.752c-10.349,0 -18.752,-8.403 -18.752,-18.752c0,-10.349 8.403,-18.752 18.752,-18.752" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M55.505,31.248l-5.43,4.833l0,-9.666l5.43,4.833Z" style="fill:white;"/>
</g>
<g id="_skewX">
<path d="M59.376,54.009c0,0 -8.402,0 -18.752,0" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M35.119,54.009l5.43,-4.833l0,9.666l-5.43,-4.833Z" style="fill:white;"/>
<path d="M40.624,45.991c0,0 8.402,0 18.752,0" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M64.881,45.991l-5.43,4.833l0,-9.666l5.43,4.833Z" style="fill:white;"/>
</g>
<g id="_skewY">
<path d="M45.991,59.376c0,0 0,-8.402 0,-18.752" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M45.991,35.119l4.833,5.43l-9.666,0l4.833,-5.43Z" style="fill:white;"/>
<path d="M54.009,40.624c0,0 0,8.402 0,18.752" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M54.009,64.881l-4.833,-5.43l9.666,0l-4.833,5.43Z" style="fill:white;"/>
</g>
<g id="_translateY">
<path d="M49.991,59.376c0,0 0,-8.402 0,-18.752" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M49.991,36.119l4.833,5.43l-9.666,0l4.833,-5.43Z" style="fill:white;"/>
<path d="M50.009,63.881l-4.833,-5.43l9.666,0l-4.833,5.43Z" style="fill:white;"/>
</g>
<g id="_rotateY">
<path d="M61.309,56.755c-8.377,2.704 -20.112,1.873 -26.189,-1.856c-6.076,-3.728 -4.207,-8.95 4.171,-11.654c8.377,-2.704 20.112,-1.873 26.189,1.856" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M50,70.007l0.603,-40.014" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M67.725,46.583l-7.1,-0.694l7.825,-2.525l-0.725,3.219Z" style="fill:white;"/>
</g>
<g id="_rotateX">
<path d="M42.322,60.407c-1.973,-8.58 -0.133,-20.199 4.105,-25.932c4.238,-5.732 9.279,-3.421 11.252,5.159c1.972,8.579 0.132,20.199 -4.106,25.932" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M70.007,50.323l-40.014,-0.603" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M51.903,67.675l1.303,-7.014l1.842,8.013l-3.145,-0.999Z" style="fill:white;"/>
</g>
<g id="_rotateZ">
<path d="M45.325,57.257c-1.406,-6.116 -0.161,-14.311 2.778,-18.287c2.94,-3.976 6.468,-2.238 7.874,3.879c1.406,6.117 0.161,14.311 -2.778,18.287" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M62.878,40.62l-25.756,18.518" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M51.739,62.431l0.828,-4.904l1.358,5.638l-2.186,-0.734Z" style="fill:white;"/>
</g>
<g id="_translateX">
<path d="M40.624,49.991c0,0 8.402,0 18.752,0" style="fill:none;stroke:white;stroke-width:2px;stroke-linecap:butt;"/>
<path d="M63.881,49.991l-5.43,4.833l0,-9.666l5.43,4.833Z" style="fill:white;"/>
<path d="M36.119,50.009l5.43,-4.833l0,9.666l-5.43,-4.833Z" style="fill:white;"/>
</g>
</svg>
<div class="style"></div>
@import url(https://fonts.googleapis.com/css?family=Inconsolata:400,700|Open+Sans:400,800);
:root {
--fast-animation: .4s;
}
html, body {
font-family: 'Open Sans', sans-serif;
background: black;
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
}
* {
box-sizing: border-box;
transform-style: preserve-3d;
}
button {
clear: both;
width: 64%;
margin-bottom: 5px;
font-size: 20px;
border-radius: 3px;
color: black;
background: #eee;
}
button:active {
box-shadow: none;
outline: none;
}
h1, h2 {
color: white;
font-weight: 300;
position: absolute;
left: .5em;
z-index:10;
text-shadow: 2px 2px 0px rgba(220,220,220,0.5), 2px 2px 0px rgba(0,0,0,0.5);
}
h2 {
top: 0;
margin: 250px 0 0 350px;;
}
#no1 {
perspective: 250px;
transform: skewX(120deg);
transition: all 2.5s;
z-index: 1;
position: absolute;
left: 25vw;
top: 25vh;
}
.container, .container * {
z-index: 1;
}
.controls {
position: absolute;
z-index: 1110;
height: 10vh;
top: 0;
right: 0;
width: 430px;
padding-top: 20px;
}
.pair {
display: flex;
color: white;
}
.pair label {
margin-top: 10px;
}
/* https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ */
input {
height: 40px;
}
input[type=range] {
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */
width: 64%; /* Specific width is required for Firefox. */
background: transparent; /* Otherwise white in Chrome */
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type=range]:focus {
outline: none; /* Removes the blue border. You should probably do some kind of focus styling for accessibility reasons though. */
}
input[type=range]::-ms-track {
width: 100%;
cursor: pointer;
/* Hides the slider so custom styles can be added */
background: transparent;
border-color: transparent;
color: transparent;
}
/* Special styling for WebKit/Blink */
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
margin-top: -14px; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; /* Add cool effects to your sliders! */
}
/* All the same stuff for Firefox */
input[type=range]::-moz-range-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
/* All the same stuff for IE */
input[type=range]::-ms-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
input[type=range]::-webkit-slider-runnable-track {
width: 70%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #aaa;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #367ebd;
}
input[type=range]::-moz-range-track {
width: 70%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #aaa;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
input[type=range]::-ms-track {
width: 70%;
height: 8.4px;
cursor: pointer;
background: transparent;
border-color: transparent;
border-width: 16px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #2a6495;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]:focus::-ms-fill-lower {
background: #aaa;
}
input[type=range]::-ms-fill-upper {
background: #aaa;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]:focus::-ms-fill-upper {
background: #367ebd;
}
#_rotate {
transform-origin: 50% 50%;
}
svg path {
display: none;
transition: all .4s;
}
.scale #_scale,
.perspective #_perspective,
.rotate #_rotate *,
.rotateY #_rotateY *,
.rotateX #_rotateX *,
.rotateZ #_rotateZ *,
.skewX #_skewX *,
.skewY #_skewY *,
.translateY #_translateY *,
.translateX #_translateX *{
display: block;
transition: all .4s;
}
.fast #no1 {
transition: all var(--fast-animation);
}
.style {
position: fixed;
bottom: 10px;
left: 10px;
color: hsla(0,0%,90%,.74);
font-family: monospace;
user-select: all;
}
var propObject = {};
const body = document.body;
const style = document.querySelector(".style");
var values = [
{
parentprop: "",
prop: "perspective",
default: "1000",
template: "%value%px",
min: "10",
max: "10000",
step: "1",
target: ".container"
},
{
parentprop: "transform",
prop: "rotate",
default: "0",
template: "%prop%(%value%deg)",
min: 0,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "rotateX",
default: "0",
template: "%prop%(%value%deg)",
min: 0,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "rotateY",
default: "0",
template: "%prop%(%value%deg)",
min: 0,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "rotateZ",
default: "0",
template: "%prop%(%value%deg)",
min: 0,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "scale",
default: "1",
template: "%prop%(%value%)",
min: "0",
max: "6",
step: ".05"
},
{
parentprop: "transform",
prop: "skewX",
default: "0",
template: "%prop%(%value%deg)",
min: -360,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "skewY",
default: "0",
template: "%prop%(%value%deg)",
min: -360,
max: 360,
step: 1
},
{
parentprop: "transform",
prop: "translateX",
default: "0",
template: "%prop%(%value%px)",
min: -1500,
max: 1500,
step: 1
},
{
parentprop: "transform",
prop: "translateY",
default: "0",
template: "%prop%(%value%px)",
min: -1500,
max: 1500,
step: 1
}
];
var controls = document.querySelector(".controls"),
target = document.querySelector("#no1"),
btnReset = document.querySelector(".reset"),
toggle = true;
btnReset.onclick = reset;
/*
{
prop:
{
parentProp,
value,
target
}
}
*/
var targetProps = {};
values.forEach(function (controle) {
addControl(controle);
});
function addControl(controle) {
var ele = getElement("input", {
type: "range",
value: controle.default,
min: controle.min,
max: controle.max,
step: controle.step,
class: "control " + controle.prop,
prop: controle.prop,
target: controle.target || "#no1",
parentprop: controle.parentprop,
default: parseTemplate(controle.template, controle.prop, controle.default),
template: controle.template
});
var lbl = getElement("label", {});
ele.oninput = ele.onclick = propChanged;
var div = getElement("div", { class: "pair" });
div.appendChild(ele);
div.appendChild(lbl);
controls.appendChild(div);
propChanged(ele);
}
let currentProp, hideTimer;
function showAxis(prop) {
if (currentProp !== null) body.classList.remove(currentProp);
currentProp = prop;
body.classList.add(currentProp);
body.classList.add("fast");
if (hideTimer) {
clearTimeout(hideTimer);
}
if (propObject[prop]) {
switch (prop) {
case "rotate":
propObject["rotate"].style.transform = targetProps[prop].value;
break;
}
}
hideTimer = setTimeout(() => {
body.classList.remove(currentProp);
body.classList.remove("fast");
currentProp = null;
}, 1000);
}
function propChanged(e) {
var targ = e.target ? e.target : e,
prop = targ.getAttribute("prop"),
defValue = targ.getAttribute("default"),
parentProp = targ.getAttribute("parentprop"),
template = targ.getAttribute("template"),
propTarget = targ.getAttribute("target"),
lbl = document.querySelector("." + prop + " + label");
showAxis(prop);
var attValue = parseTemplate(template, prop, targ.value);
lbl.innerText = prop + " " + targ.value;
targetProps[prop] = {
parentProp: parentProp,
value: attValue,
target: propTarget ? propTarget : "#no1",
defValue: defValue
};
updateProperties(target);
}
function reset() {
updateProperties(target, toggle);
toggle = !toggle;
}
function updateProperties(ele, bDefault) {
var props = {};
const keys = Object.keys(targetProps);
keys.forEach((key) => {
var obj = targetProps[key],
parentProp = obj.parentProp || key;
var val = bDefault ? obj.defValue : obj.value;
if (typeof props[parentProp] === "undefined") {
props[parentProp] = { value: val, target: obj.target };
} else {
props[parentProp].value += " " + val;
}
});
let styles = "";
const keys = Object.keys(props);
keys.forEach((key) => {
var propTarget = document.querySelector(props[key].target);
propTarget.style[key] = props[key].value;
styles += (styles === "" ? "" : "; ") + key + ": " + props[key].value;
});
style.innerText = styles;
}
function parseTemplate(temp, prop, value) {
var res = temp.replace(/%prop%/gi, prop),
res = res.replace(/%value%/gi, value);
return res;
}
function getElement(tagName, attributes) {
var ele = document.createElement(tagName);
if (attributes) {
const keys = Object.keys(attributes);
keys.forEach((key) => {
ele.setAttribute(key, attributes[key]);
});
}
return ele;
}
values.forEach((controle) => {
propObject[controle.prop] = document.getElementById("_" + controle.prop);
});
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.