您现在的位置是:首页 > 文章详情

前端如何优雅实现0到auto的高度过渡

日期:2024-10-16点击:174

各位好,相信大家都知道,最近更新Chrome已经支持了0到auto的高度过渡。但是很多人反映这种特性太新了,出于兼容考虑用不了的。而实际上calc-size是可以渐进增强的。今天我就给大家表演一下,0到auto的渐进增强兼容所有浏览器。

我们先搭建一个空白工程化项目

这个示例工程。是一个计数器。

import * as React from "react";
import { Component } from "react";

interface AppProps { }
interface AppState {
	count: number;
}

export default class App extends Component<AppProps, AppState> {
	constructor(props: AppProps) {
		super(props);
		this.increase = this.increase.bind(this);
		this.decrease = this.decrease.bind(this);
		this.state = {
			count: 0
		};
	}

	private decrease() {
		this.setState({
			count: this.state.count - 1
		});
	}

	private increase() {
		this.setState({
			count: this.state.count + 1
		});
	}

	render() {
		var { count } = this.state;
		return <>
			<h1>Hello World!</h1>
			<div>
				<button type="button" onClick={this.decrease}>-</button>
				{count}
				<button type="button" onClick={this.increase}>+</button>
			</div>
		</>;
	}
}

接下来我们创建一个组件

这个组件有展开和收起2种状态。修改传入的属性,可以切换className

import * as React from "react";
import { Component } from "react";
import "./CollapseBody.scss";

export interface CollapseBodyProps {
	open?: boolean;
}

export class CollapseBody extends Component<CollapseBodyProps> {
	render() {
		let { open, children } = this.props;
		let classList = ["collapse-body"];
		if(open) {
			classList.push('collapse-body_open');
		} else {
			classList.push('collapse-body_close');
		}
		return <div className={classList.join(" ")}>
			{children}
		</div>;
	}
}

接下来我们引入组件

 直接在刚刚的计数器上改一下,这样在计数的时候就会切换展开收起状态。

import * as React from "react";
import { Component } from "react";
import { CollapseBody } from "./Components/Collapse/CollapseBody";

interface AppProps { }
interface AppState {
	count: number;
}

export default class App extends Component<AppProps, AppState> {
	constructor(props: AppProps) {
		super(props);
		this.increase = this.increase.bind(this);
		this.decrease = this.decrease.bind(this);
		this.state = {
			count: 0
		};
	}

	private decrease() {
		this.setState({
			count: this.state.count - 1
		});
	}

	private increase() {
		this.setState({
			count: this.state.count + 1
		});
	}

	render() {
		var { count } = this.state;
		return <>
			<h1>Hello World!</h1>
			<div>
				<button type="button" onClick={this.decrease}>-</button>
				{count}
				<button type="button" onClick={this.increase}>+</button>
			</div>
			<CollapseBody open={count % 2 === 0}>
				asdasdas
			</CollapseBody>
		</>;
	}
}

接下来我们看看效果

我们可以看到按钮时class在切换

接下来编写样式

展开时高度是calc-size(auto , size);收起时,高度是0;在加以transition和overflow就完成了。

我们试一下,在高版本正常过渡,低版本由于不支持calc-size(auto, size),于是高度为默认值auto,没有过渡动画,但是不影响使用。

.collapse-body {
	transition: height .3s;
	overflow-y: hidden;
	height: calc-size(auto, size);
}

.collapse-body_close {
	height: 0;
}

overflow和display优化

上面代码虽然能用但是还不够完美,有2个问题。

  • 首先容器含有overflow:hidden,会导致内部内容被截断,如果内部内容还有box-shadow,很容易被截掉。最好是只在过渡时含有overflow:hidden。
  • 还有收起后应当含有disaplay:none,否则收起后仍然占据体积,在一些情况下会出现不必要的滚动条。

我们可以使用animation进行改造。

.collapse-body_close {
	display: none;
}

@supports(height: calc-size(auto, size)) {
	.collapse-body_open {
		animation: collapseBodyIn .3s;
	}

	.collapse-body_close {
		animation: collapseBodyOut .3s;
	}
}

@keyframes collapseBodyIn {
	from {
		overflow-y: hidden;
		height: 0;
	}

	to {
		overflow-y: hidden;
		height: calc-size(auto, size);
	}
}

@keyframes collapseBodyOut {
	from {
		overflow-y: hidden;
		display: block;
		height: calc-size(auto, size);
	}

	to {
		overflow-y: hidden;
		display: block;
		height: 0;
	}
}

出现动画

上面示例首次出现时也有动画,假如不想要首次出现的动画,只有切换时才有动画,可以在组件上控制。

import * as React from "react";
import { Component } from "react";
import "./CollapseBody.scss";

export interface CollapseBodyProps {
	open?: boolean;
}

export class CollapseBody extends Component<CollapseBodyProps> {
	private first = true;
	componentDidMount(): void {
		this.first = false;
	}
	render() {
		let { open, children } = this.props;
		let classList = ["collapse-body"];
		if(!open) {
			classList.push('collapse-body_close');
		} else if(!this.first) {
			classList.push('collapse-body_open');
		}
		return <div className={classList.join(" ")}>
			{children}
		</div>;
	}
}

最后看看效果

非常的完美

最后我们再看看低版本浏览器的效果

先点构建,我这里配置的构建脚本已经,包含了语法转义和polyfill,也用了anujs,因此react的兼容性可以不用操心,我们只看CSS效果。

我们直接上难度挑战IE6,我们发现在在IE6中没有过渡效果,而是直接隐藏显示,并不影响实际使用,非常地优雅

原文链接:https://my.oschina.net/linsk1998/blog/16354232
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章