') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); CSS3之3d transform · Issue #2 · simaQ/cssfun · GitHub
Skip to content

CSS3之3d transform #2

Description

@simaQ

原文地址: Intro to css 3D transforms

前言
作者的这个introduction已经写了有好几年了,我今年(而且今年都快过去了)才看到...果真是渣渣...那句话,人丑朋友又少真的是要多读书。不过我觉得我还是得厚着大脸皮敲下去...

三维世界的坐标系

文章开始之前先来张坐标系图好让大家有个3D概念
1

透视,perspective属性

为了激活3D属性,需要对元素声明perspective属性。有两种声明的方式:

  1. 作为属性transform的值和transform一起声明,就同如下代码一样

    transform:perspective( 600px );
  2. 直接使用 perspective属性 声明

    perspective:600px;

例子1: 点击访问demo

#red .box {
background-color: red;
transform:perspective( 600px ) rotateY( 45deg ); /*作为transform的值*/
}
#blue {
perspective:600px; /* 直接声明perspective属性 */
}
#blue .box {
background-color: blue;
transform:rotateY( 45deg );
}

perspective01

这两种方式都能产生3D效果,看上去是产生了一样的效果,但是其实两者还是不同的。transform值的形式适用于单个元素的3D转换效果,就像上个例子一样。但是如果应用于多个元素的话,发生变换的元素并不会表现出一致的效果。因为如果对每个不同位置的元素声明一样的transform属性值,那么他们就会拥有个各自的3D空间的基点了。为了解决这个问题,需要对父元素声明perspective属性,使每个子元素共享一个3D空间了。

例子2: 点击访问demo
perspective-children01

#red figure {
background: red;
transform: perspective( 400px ) rotateY(45deg);
}
#blue {
perspective: 400px;
}
#blue figure {
background: blue;
transform: rotateY( 45deg );
}

PS: 看不出效果的话,可以改变下perspective的值,这样看到的差别会明显一点

perspective值的大小决定了3D效果的强弱程度。就像人看物体一样,perspective值越大,代表物体离眼睛的距离越远,这样看到的物体就越小。perspective:2000px,产生的效果就像我们用望远镜看一个很远很远的物体,perspective: 100px; 则会让物体看起来很大,就像一只小虫看巨大的物体一样。

元素的3D空间的默认基点坐标位于元素中央。但是可以通过perspective-origin属性来修改: perspective-origin: 25% 75%;

例子3 : 点击访问demo

浏览器支持情况

目前的浏览器支持情况如下: 详情请点击查看
2

3D transform functions

bpj d79g j fpb m enl8c
废话我就不翻译了。。。

3D转换和2D转换方法基本相同,下面就是3D转换方法:

  • rotateX( angle )
  • rotateY( angle )
  • rotateZ( angle )
  • translateZ( tz )
  • scaleZ( sz )

但是不同的是, translateX()方法是使一个元素沿着水平X轴坐标旋转,translateZ()则是沿着Z坐标轴,可以使物体在3D空间从前往后移动。值为正数且越大则元素离屏幕越近,负数则代表离屏幕远。

rotate方法使物体在相应的坐标系进行旋转。不过注意哦,rotateX可不是从二维空间中的从左到右的旋转,而是围绕真文章最开头给大家温习的那张3D图中的X轴旋转,具体看下面的例子。

3D transform也提供了一些简写方法,使用这些方法需要同时声明三个维度的参数:

  • translate3d( tx, ty, tz )
  • scale3d( sx, sy, sz )
  • rotate3d( rx, ry, rz, angle )

提示: 这些3D方法都能够触发Safari的硬件加速,Dean Jackson, CSS 3D transform 技术规范的作者以及主要的Webkit成员这么写道:

“实际上,任何transform的3D操作都会触发硬件加速,即使实际只做了2D转换或者什么也没有做(就像translate3d(0,0,0))。但是这只是目前如此并不代表将来就不会发生变化,这也就是为什么我们没有形成文档或者鼓励这样做的原因。但是这在有些场景下确实很有帮助,可以显著提高渲染的性能。”

这里作者为了简单起见,例子上都只是用了一些基本的转换方法,但是如果你需要在IOS或者Safari的生产环境下使用CSS的话,最好使用foo3d()(指的3D transform的简写方法)来获取最好的渲染性能。

活学活用

1. 卡片翻转

现在大家应该都知道了如何制作3D效果。那就先实现个简单卡片翻转的例子吧。
先看看效果: 请点击

<!-- html结构 --><sectionclass="container"><divid="card"><figureclass="front">1</figure><figureclass="back">2</figure></div></section>

.container 作为舞台元素,声明perspective:800px;属性

.container { width:200px;
height:260px;
position: relative;
perspective:800px;
}

现在#card就可以在container的3D空间内进行各种变换了,声明width: 100%; and height: 100%;是为了保证transform-origin为container的中央位置

#card {
width:100%;
height:100%;
position: absolute;
transform-style: preserve-3d;
transition: transform 1s;
}

transform-style属性有两个参数,flat|preserve-3d. 前者flat为默认值,表示平面的;后者preserve-3d表示3D透视。一般而言,该声明应用在3D变换的兄弟元素们的父元素上,也就是舞台元素。

backface-visibility: hidden; 当前面元素遮挡住后面的元素时,声明这个属性就可以产生遮挡的效果。

#cardfigure {
display: block;
position: absolute;
width:100%;
height:100%;
backface-visibility: hidden;
}

首先视觉上我们只能看到.front的卡片,所以需要将.back的卡片沿着Y轴旋转180度至后方,当点击flip按钮的时候,直接让#card再沿着Y轴旋转180度,这个时候front卡片就到视线后方而back卡就被我们看到了。

#card .front {
background: red;
}
#card .back {
background: blue;
transform:rotateY( 180deg );
}
#card.flipped {
transform:rotateY( 180deg );
}

如果我们想要改变旋转轴的位置呢? 这就是transform-origin的作用了,稍作修改就可以达到以下的效果。
我要更炫点: 请点击

#card { transform-origin: right center; }
/* translateX( -100% ) 使元素沿着X轴发生平移 */#card.flipped {
transform:translateX( -100% ) rotateY( -180deg );
}

2. 立方体

DEMO:
cube1
cube2

这个例子主要向大家介绍下translateZ()方法,它可以帮你理解透视位置。demo

对于没有rotateX以及rotateY的元素,translateZ的功能就是让元素在自己的眼前或近或远。比方说,我们设置元素perspective为201像素,如下:
perspective: 201px;
则其子元素,设置的translateZ值越小,则子元素大小越小(因为元素远去,我们眼睛看到的就会变小);translateZ值越大,该元素也会越来越大,当translateZ值非常接近201像素,但是不超过201像素的时候(如200像素),该元素的大小就会撑满整个屏幕(如果父辈元素没有类似overflow:hidden的限制的话)。因为这个时候,子元素正好移到了你的眼睛前面,所谓“一叶蔽目,不见泰山”,就是这么回事。当translateZ值再变大,超过201像素的时候,该元素看不见了——这很好理解:我们是看不见眼睛后面的东西的!
引用自 张鑫旭老师的http://www.zhangxinxu.com/wordpress/2012/09/css3-3d-transform-perspective-animate-transition/

**但是这里需要注意的是translateZ 和 rotate 方法的顺序,顺序的不同会产生不一样的效果。**可以通过以下例子好好感受下~
translateZ

3. 旋转木马

旋转木马

这里主要向大家介绍旋转木马效果计算各个面板translateZ值的方法:

  • 我们现在只知道两个值:
    1. rotateY 的旋转角度(等分,通过 360/元素个数 取得)
    2. 面板的宽

那问题来了,怎么计算translateZ的值呢? 其实很简单,当然不是凭直觉随便选出来的那种简单,因为它还是有公式的,那就用下面这张图来说明吧:
diagram
然后我们就可以计算出 r 的值了~
calc

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions