css实现保持元素宽高比

原理

  1. 元素的padding值如果使用百分比,那这个百分比是相对于父元素宽度而言的,padding-top和padding-bottom指定百分比时也是相对于父元素高度而言;
  2. IE盒模型中,width = content + padding + border,因此只设置padding也会使元素在页面上占据一部分区域;chromium内核浏览器大多采用IE盒模型而非W3C标准盒模型;

验证

写两个元素,父元素宽高200px,子元素padding为20%,可以在调试器里看到,四边padding都是20px;


<html>
<head>
	<style type="text/css">
		.outter {
			width: 200px;
			height: 200px
		}
		.inner {
			padding: 10%;
		}
	style>
head>
<body>
	<div class="outter">
		<div class="inner">
		div>
	div>
body>
html>

截图里,.outter是父元素,右下角盒模型是.inner;
思考:为什么.inner的盒模型中,content区域是160*0?
css实现保持元素宽高比_第1张图片

应用

实现保持宽高比

以实现宽高比为 11:9 为例。宽高比11:9,则高为宽的0.8181(=9/11),所以设置padding-top为81.81%,这样inner占据的高度就是outter宽度的81.81%。如下图,可以看到inner的高度为163.61=200*81.81%,实现了inner在页面中占据的空间宽高比为9/11。
css实现保持元素宽高比_第2张图片
但此时如果在inner内部放入其他元素的话,会因为padding-top的存在,导致元素无法从outter的顶部开始排列,如下图。
css实现保持元素宽高比_第3张图片
这时候需要为inner设置position:relative; 然后在inner内部设置一个容器宽高为100%,position:absolute; 元素放在inner内部容器中,即可从outter的顶部开始排列元素;


<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<style type="text/css">
		.outter {
			width: 200px;
			height: 200px
		}
		.inner {
			padding-top: 81.81%;
			position: relative;
		}
		.inner>.inner-content {
			width: 100%;
			height: 100%;
			position: absolute;
			top: 0;
			left: 0;
		}

		img {
			width: 100%;
			height: 100%;
		}
	style>

head>
<body>
	<div class="outter">
		<div class="inner">
			<div class="inner-content">
				<img src="https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268/sign=2e12f29caa4bd11304cdb03462aea488/377adab44aed2e736d5390c38001a18b86d6faa3.jpg">
			div>
		div>
	div>
	<h1>okh1>
body>
html>

css实现保持元素宽高比_第4张图片
这里需要注意,如果inner-content中内容过多导致高度超出inner-content的height,会直接渲染到页面上,而不占据多余的页面空间(因为inner-content已经拉出文档流),有可能会遮挡outter下面的内容。因此需要根据情况设置inner-content的overflow:hidden; 或 overflow:auto;

Vue中,实现保持宽高比的组件

根据以上的实现方式,可以自定义一个vue组件,用于保持宽高比。

<template>
    <div class="outter" :style="formattedRatioStyle">
        <div class="inner">
            <div class="inner-content">
                <slot>slot>  
            div>
        div>
    div>
template>

<script>
    export default {
      data() {
        return {};
      },

      props: ['ratio', 'overflow', 'overflowX', 'overflowY'],

      computed: {
        formattedRatioStyle() {
          let ratio = this.ratio;
          if (ratio == null || Number.isNaN(ratio)) {
            ratio = 100;
          }
          if (typeof ratio !== 'string' || !ratio.endsWith('%')) {
            ratio = ratio + '%';
          }
          return `padding-top: ${ratio};`;
        },

        formattedContentStyle() {
          const styles = [];
          if (this.overflow) {
            styles.push('overflow:' + this.overflow);
          }
          if (this.overflowX) {
            styles.push('overflow-x:' + this.overflowX);
          }
          if (this.overflowY) {
            styles.push('overflow-y:' + this.overflowY);
          }
          return styles.join(';');
        },
      }

    }
script>

<style scoped lang="scss">
    .outter {
        width: 100%;
        height: 0;
        position: relative;

        .inner {
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
        }
    }
style>

使用

<aspect-ratio ratio="81.81" overflow="auto">aspect-ratio>

你可能感兴趣的:(前端)