Подробное объяснение 5 реализаций схемы водопадного потока и объектной подгонки.

внешний интерфейс CSS

В недавних проектах приходится иметь дело с компоновкой, связанной с изображениями.Я должен сказать, что изображения действительно требуют некоторых усилий, чтобы получить идеальный эффект отображения. Потому что размер или пропорции изображений различаются. Поэтому, если вы хотите, чтобы изображения разных размеров имели хороший эффект отображения, вам нужно найти подходящий способ.

А картинки часто являются незаменимым элементом. В конце концов, картинка стоит тысячи слов, а иногда картинки могут принести отличный результат.

Например, смайлики, которые мы используем каждый день, часто могут выражать информацию, которую мы не можем описать словами. Например, мультфильмы, которые мы часто видим в пабликах, состоят всего из нескольких слов, но они могут заставить нас много читать.

Конечно, если мы являемся веб-сайтом с изображениями, обработка изображений является неизбежной темой. Поскольку у меня нет большого опыта в обработке изображений, я использую его по мере изучения. Сегодня я разберу знания, связанные с картинками, которые я недавно выучил.

Например, как лучше отобразить отдельное изображение, и какие методы реализации каскадного потока вы не знаете.

Далее перейдем сразу к теме, начнем с отображения одиночного изображения.

Установите ширину или высоту на 100%

Из-за уникальности самой картинки:

  1. Если ширина и высота не заданы, они будут отображаться на веб-странице в соответствии с исходным размером. То есть насколько большой, насколько большой отображается.
  2. В случае непропорционального масштабирования он будет растягиваться и деформироваться.
  3. При установке ширины или высоты будет сохранено исходное соотношение сторон для масштабирования.

<style lang="scss" scoped>
.box1 {
  width: 150px;
  height: 150px;
  border: 2px solid red;
}
.box2 {
  width: 150px;
  height: 100px;
  border: 2px solid red;
  img {
    display: block;
    width: 100%;
    height: 100%;
  }
}
</style>

Очевидно, что когда мы используем 1 или 2 метода, это очень разрушительно и не может быть применено к реальным проектам.

Поэтому часто мы будем использовать третий способ в проекте, который заключается в установке высоты или ширины. Он сохранит исходное соотношение для масштабирования.

<style lang="scss" scoped>
.box {
  width: 150px;
  height: 150px;
  border: 2px solid red;
}
.img1 {
  width: 100%;
}
.img2 {
  height: 100%;
}
</style>

Но здесь снова возникает проблема, изображение либо выходит за пределы контейнера, либо остается пустым, если только соотношение сторон контейнера не будет точно равно соотношению сторон изображения, тогда оно подойдет идеально.

Для изображений за пределами контейнера мы можем использоватьoverflow: hiddenСкрыть лишнее. Картинки отображаются хорошо. Но соответственно мы теряем и часть видимой области изображения.

Итак, на данный момент вам нужно выбрать в соответствии с вашими потребностями, скрыть ли часть изображения или оставить пустым. Некоторые друзья скажут, что наши продукты сказали, что нет проблем с деформацией изображения, вы можете просто заполнить контейнер для меня. Отлично....

Тем не менее, вы должны внимательно прочитать эту статью, потому что потребности постоянно меняются, и нет никакой гарантии, что они вам когда-нибудь понадобятся.

Другой друг сказал: что, если эти два продукта не соответствуют нашим потребностям, есть ли другой способ? Ответ обязателен, посмотрим вместе.

object-fit

Свойство CSS3 object-fit используется для указания того, как содержимое «заменяемого элемента» помещается в контейнер. Имеет 5 значений. Они есть:fill | contain | cover | none | scale-down. Давайте сначала посмотрим на эффекты, чтобы объяснить, что они означают.

<template>
  <div class="box">
    <img src="https://picsum.photos/id/1027/200/300"/>
  </div>
</template>
<style lang="scss" scoped>
.box {
  width: 150px;
  height: 150px;
  border: 2px solid red;
  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
</style>

Увидев вышеупомянутый эффект отображения, не сложно понять.

  • Заполните: заполнит весь контейнер, соотношение сторон не рассматривается, это будет деформация растяжения.
  • содержат: будет масштабироваться до контейнера, сохраняя соотношение сторон.
  • обложка: будет сохранен коэффициент масштабирования, размер содержимого должен быть больше или равен размеру контейнера, а затем обрезан.
  • нет: сохранить исходный размер изображения.

а такжеscale-downЕсть два представления, поэтому давайте рассмотрим их по отдельности.

  • масштабирование: будет выбрано одно из значений: нет или содержание.Принцип таков: когда контейнер маленький, его производительность такая же, как и у содержимого; когда изображение маленькое, его производительность такая же, как и у пустого. То есть кто моложе кого выбирает.

Не знаю, есть ли здесь такие друзья, как я.. Когда я увидел разные исполнения картинок, я зашел в браузер, чтобы проверить их.<img>истинного размера, открытие остаетсяwidth: 100%;height: 100%;заключается в заполнении всего контейнера.

Но почему отображение контента имеет разные эффекты, что заставляет задуматься. В духе открытий и исследований я отправился на поиски ответа.

W3c описывает это так:<img>Тег создает заполнитель для ссылочного изображения.

И Чжан Синьсюй в этом очень заинтересован.Полуглубокое понимание свойств CSS3 object-position/object-fitВ статье также говорится:

<img>Элементы на самом деле не зависят от содержимого.<img>Это эквивалентно оболочке, обертывающей содержимое. все, что вы контролируете<img>Размер элемента. Размер содержимого определяетсяobject-fitконтроль собственности.

С учетом вышеизложенного,<img>является заполнителем пробела и не управляет содержимым. Понимаю. Я чувствую, что снова делаю успехи. Каждый раз, когда вы исследуете, вы открываете что-то новое, и это прекрасное чувство. В частности, она разбита на статьи и предоставлена ​​всем для изучения.

Зная это, мы будем более удобными при манипулировании изображениями. Это конец? Нет, нет, это только начало, а самое интересное еще впереди. Компоновка сзади еще интереснее.

макет с несколькими изображениями

То, что было сказано выше, является отображением одного изображения. Пока мы помещаем изображение в контейнер подходящим образом. А если это список картинок? Или веб-сайт, предназначенный для отображения изображений, будет иметь большое количество изображений различных размеров и пропорций.

Предположим, мы хотим добиться эффекта картинной галереи. Сначала мы придаем изображениюfloat: left, но поскольку размер изображений разный, высота каждого изображения разная, и изображения в следующем ряду будут слипаться, что приведет к беспорядку.

На этом этапе вы должны установить высоту контейнера так, чтобы изображение могло быть выровнено по нижнему краю, но, как мы упоминали в начале статьи, изображение либо превышает высоту контейнера, либо остается пустым.

тогда, если вы используетеobject-fitАтрибуты управляют контентом в соответствии с потребностями бизнеса, что, кажется, способно выполнить задачу.

Мы устанавливаем значение для содержимого, и с макетом проблем нет, но на самом деле он очень неприглядный. Если он установлен на обложку, если изображение слишком большое, большая часть контента будет потеряна и невидима. Как сделать? Каково решение? В этом преимущество схемы водопадного потока.

Макет водопада не будет выглядеть загроможденным и позволит максимально отображать содержимое изображения. Поэтому этот метод компоновки выбирают многие веб-сайты с фотографиями.

В настоящее время существует две формы схемы водопадного потока: одна — с равной шириной, а другая — с равной высотой. Сначала поговорим о моноширине.

Водопад одинаковой ширины

См. выше, какова ваша идея реализации? Вы можете подумать несколько секунд, а затем давайте посмотрим, есть ли у какой-либо из этих реализаций та же идея, что и у вас.

Идея 1. JS считает количество столбцов

Ключевые идеи:

  • Сначала установите ширину столбца, а затем рассчитайте количество отображаемых столбцов.
  • Добавьте изображения в каждый столбец.

Ключевой код:

<script>
export default {
  methods: {
     //计算图片列数
    getColNumbers() {
      let clientWidth = this.$refs.waterfall.clientWidth
      this.colNumbers = Math.floor(clientWidth / this.colWidth)
    },
    //读取图片
    loadImage() {
      this.getColNumbers()
      for (let i = 0; i < 17; i++) {
        let colIndex = i % this.colNumbers
        let url = require(`@/assets/images/${i}.jpg`)
        if (this.imgList[colIndex]) {
          this.imgList[colIndex].push(url)
        } else {
          this.$set(this.imgList, colIndex, [url])
        }
      }
    },
  }
}
</script>

Преимущество: Идея ясна и проста, не нужно делать слишком много вычислений, просто рассчитайте количество отображаемых столбцов, а затем добавьте изображения.

недостаток: Конец каждого столбца может быть недостаточно удобным, некоторые столбцы могут быть очень длинными, а некоторые — очень короткими.

Идея 2. Используйте абсолютное позиционирование

Ключевые идеи:

  • Сначала установите ширину столбца, а затем рассчитайте количество отображаемых столбцов.
  • Установите для изображения абсолютное позиционирование, а затем вычислите верхнее и левое значения каждого изображения.
  • Сначала упорядочите первый ряд изображений, верхний — 0, левый — индекс столбца * ширина столбца.
  • Начиная со второй строки каждое изображение помещается под самый короткий столбец. Затем увеличьте высоту этого столбца, в это время высота столбца изменится, а следующая картинка будет искать другие самые короткие столбцы. Продолжайте рассчитывать на это.

Ключевой код:

<script>
export default {
  methods: {
    //计算图片列数
    getColNumbers() {
      let clientWidth = this.$refs.waterfall.clientWidth
      this.colNumbers = Math.floor(clientWidth / this.colWidth)
    },
    //读取图片
    loadImage() {
      this.getColNumbers()
      for (let i = 0; i < 17; i++) {
        let image = new Image()
        let url = require(`@/assets/images/${i}.jpg`)
        image.src = url
        image.onload = () => {
          this.render({
            index: i,
            url: url,
            ratio: image.width / image.height
          })
        }
      }
    },
    render(imgInfo) {
      let colIndex = imgInfo.index % this.colNumbers
      imgInfo.left = colIndex * this.colWidth
      //首行 top为 0,记录每列的高度
      if (imgInfo.index < this.colNumbers) {
        imgInfo.top = 0
        this.colHeight[colIndex] = this.colWidth / imgInfo.ratio
      } else {
        //获取高度的最小值
        let minHeight = Math.min.apply(null, this.colHeight)
        let minIndex = this.colHeight.indexOf(minHeight)
        //此图片的 top 为上面图片的高度,left 相等
        imgInfo.top = minHeight
        imgInfo.left = minIndex * this.colWidth
        //把高度加上去
        this.colHeight[minIndex] += this.colWidth / imgInfo.ratio
      }
      this.imgList.push(imgInfo)
    }
  }
}
</script>

Преимущество: поскольку изображение, добавляемое каждый раз, представляет собой самый короткий столбец, отображение в конце будет намного удобнее, чем в идее 1.

недостаток: Верхнее и левое значения будут рассчитаны один раз, если одно из них не будет отображаться. И порядок картинок не тот.

Идея 3. Свойство столбца CSS3

Ключевые идеи:

  • количество столбцов: укажите количество столбцов
  • column-gap: установить зазор между столбцами

Ключевой код:

<template>
  <div class="waterfall-width-column">
    <div class="image-box" v-for="img in imgList" :key="img">
      <img :src="img" alt="" />
    </div>
  </div>
</template>
<style lang="scss" scoped>
.waterfall-width-column {
  column-count: 3;
  column-gap: 10px;
  .image-box {
    img {
      display: block;
      width: 100%;
    }
  }
}
</style>

Преимущество: проще, без дополнительных вычислений и эффективного рендеринга напрямую с помощью CSS.

недостаток: Порядок изображений сверху вниз, что зависит от бизнес-требований. Кроме того, количество столбцов фиксировано.

Но вы можете попробовать установить другое количество столбцов с помощью медиа-запроса.

@media (min-width: 768px) {
  .waterfall-width-column {
    column-count: 3;
  }
}
@media (min-width: 992px) {
  .waterfall-width-column {
    column-count: 4;
  }
}
@media (min-width: 1200px) {
  .waterfall-width-column {
    column-count: 6;
  }
}

Контурный водопад

После разговора о типе равной ширины, давайте поговорим о типе равной высоты.

Идея 1. JS рассчитывает масштабирование

  • Сначала укажите базовую высоту
  • Изображение получает ширину ниже эталонной высоты, а затем вычисляет, сколько изображений можно разместить в каждой строке.
  • В этот момент каждая строка изображений будет определенно меньше ширины контейнера, а затем эта строка будет масштабирована до размера контейнера. Пересчитайте высоту после увеличения.

Ключевой код:

<script>
export default {
  data() {
    return {
      baseHeight: 200, //图片的基础计算高度
      imgList: [[]], //用二维数据保存每一行数据
      rowWidth: 0, //每行的图片宽度
      rowCount: 0 //每行的索引
    }
  },
  methods: {
    loadImage() {
      for (let i = 0; i < 17; i++) {
        let image = new Image()
        let url = require(`@/assets/images/${i}.jpg`)
        image.src = url
        image.onload = () => {
          this.compare({
            url: url,
            width: this.baseHeight * (image.width / image.height),
            height: this.baseHeight
          })
        }
      }
    },
    //缩放后的总图片宽度与屏幕宽度比较
    compare(image) {
      //容器宽度
      let clientWidth = this.$refs.waterfall.clientWidth
      //计算每行宽度
      this.rowWidth += image.width
      //如果宽度大于容器宽度,去掉多余的宽度,整体进行缩放适应容器让右边对齐
      if (this.rowWidth > clientWidth) {
        //减去每个css padding边距
        clientWidth = clientWidth - this.imgList[this.rowCount].length * 10
        this.rowWidth = this.rowWidth - image.width
        //把高度调整为放大后的
        let growAfterHeight = (clientWidth * this.baseHeight) / this.rowWidth
        this.imgList[this.rowCount].forEach(item => {
          item.height = growAfterHeight
        })
        //把多余图片放入到下一行
        this.rowWidth = image.width
        this.rowCount++
        this.$set(this.imgList, this.rowCount, [image])
      } else {
        this.imgList[this.rowCount].push(image)
      }
    }
  }
}
</script>

Преимущество: содержимое изображения будет отображаться полностью и не будет скрыто.

недостаток: Требуются повторные вычисления и масштабирование.

Идея 2. Гибкая верстка

  • Сначала придайте изображению фиксированную высоту, а затем используйте функцию распределения соотношения flex-grow.
  • Установите атрибут object-fit для изображения, чтобы оно оставалось пропорциональным заполнению контейнера.
<template>
  <div class="waterfall-height-css">
    <div class="image-box" v-for="img in imgList" :key="img.url">
      <img :src="img.url" />
    </div>
  </div>
</template>
<script>
<style lang="scss" scoped>
.waterfall-height-css {
  display: flex;
  flex-wrap: wrap;
  .image-box {
    flex-grow: 1;
  }
  img {
    display: block;
    min-width: 100%;
    height: 200px;
    object-fit: cover;
  }
}
</style>

На этом этапе вы обнаружите, что изображения в каждом ряду отображаются хорошо. Но только в последней строке есть небольшая проблема.

Представьте, что если в последней строке есть только одно изображение, оно будет масштабировано для заполнения одной строки, в результате чего на изображении будет отображаться только очень небольшая часть содержимого.

Поэтому изображение в последней нашей строке можно масштабировать без масштабирования. Просто добавьте следующие свойства css.

<style lang="scss" scoped>
.waterfall-height-css {
  &:after {
    content: '';
    display: block;
    flex-grow: 99999;
  }
}
</style>

потому чтоflex-grow: 99999Значение очень велико, поэтому почти все оставшееся пространство последней строки будет занято, в результате чего изображение не будет выделено, и оно будет отображаться только в соответствии с исходным размером, и оно не будет увеличено, чтобы занять полная линия.

Преимущество: настройка CSS проста, а рендеринг эффективен.

недостаток: часть видимой области изображения будет потеряна.

До сих пор мы представили характеристики отображения изображений и способы их использования.object-fitКонтролируйте контент.

Для компоновки нескольких изображений, если вы хотите разумно отображать изображения, макет водопада является очень хорошим выбором.Конечно, если бизнес-требования не требуют удобства отображения и эстетики изображений, вы можете использовать его.object-fitКонтролируйте контент.

Но я думаю, что макет потока водопада также является одной из вещей, которые мы должны освоить. Даже если нам это не нужно в данный момент, мы можем сначала сохранить статью в случае чрезвычайной ситуации. В статье используются различные способы достижения этого. , вы можете выбрать один способ, который лучше всего соответствует вашим потребностям.

Конечно, есть еще много деталей, которые не были рассмотрены в деле.Например, при смене окна браузера картинка будет мерцать при перезагрузке.Как оптимизировать опыт? Друзья, вы могли бы также попробовать оптимизировать его самостоятельно. Практика является важным средством приобретения навыков.

Кодовые адреса для всех случаев в тексте:адрес гитхаба

Технические ресурсы 2T отправляются бесплатно, включая, помимо прочего: интерфейс, Python, Java, Android, продукты и т. д. Ответ на "1024" в фоновом режиме официального аккаунта можно получить бесплатно!

Официальный аккаунт: Шесть небольших Dengdeng, больше галантерейных товаров, справочный ответ «Jiaqun» приведет вас в группу высококачественного обмена.