background

As we all know, there is a point nine graph in Android, that is, an image is divided into nine pieces, the four corners are fixed, and other areas are stretched horizontally and vertically to meet the background function of adaptive size.

But how do you implement this in a front-end Web project? This article simplifies the problem by implementing a fixed percentage for the top and bottom, and a free stretch in the middle.

Existing technologies

1. Using border-image to implement the point-9 border-image is mainly for compatibility

Think with technology

  1. How to make background graphics dynamically scale based on content (PURE CSS)

    The content is written using the document flow, and the background div gets its parent size using absolute positioning

    <! -- lang = vue -->
    <div class="vendor-outbox"><! -- position: relative -->
        <div class="flc fl-a-c" style="position: relative;">
            <div class="vendor-list-box fl fl-w fl-j-c">
                <template v-for="(item, index) in vendors">
                    <img
                        v-if="item"
                        class="vendor-item"
                        @click="openLink(item)"
                        :src="item.imgSrc"
                    />
                    <div v-else class="vendor-item"></div>
                </template>
            </div>
        </div>
        <CustomBackgroundImage></CustomBackgroundImage>
    </div>
    Copy the code

    This code is a list of merchants, arranged two in a row using Flex and automatically extended

  2. How to show only part of an image (pure CSS)

    Hide with overflow: Hidden + transfrom: translateY()

    <! -- lang = vue -->
    <div class="custombackground-t">
        <img :src="imgSrc" style="width: 100%; transform:translateY(50%)" />
    </div>
    Copy the code
    .custombackground-t {
        overflow: hidden;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        transform: translateY(-50%);
    }
    Copy the code
  3. How do I get the rest of the div size

    In the current problem, the height of the parent element is not determined, the height of the upper part is a fixed percentage of the height of the image, the height of the lower part is a fixed percentage of the height of the image, and the rest of the height is used in the middle.

    First get the actual width and height of the picture, and then dynamic calculation

Actual code

<template>
    <div class="ab-full" style="z-index: -1" ref="imgRef"> <! This part must be overlaid under the actual content.
        <! Here is the intermediate module -->
        <div
            class="custombackground-c"
            :style="{ top: `${imgRealHeight * topPercent / 100}px`, bottom: `${imgRealHeight * bottomPercent / 100}px` }"
        >
            <img
                :src="imgSrc"
                style="width: 100%;"
                :style="{ transform: `translateY(-50%) scaleY(${centerScale})` }"
            />
        </div>
        <! -- Top module -->
        <div class="custombackground-t" :style="{ transform: `translateY(${topPercent - 100}%)` }">
            <img
                :src="imgSrc"
                style="width: 100%;"
                :style="{ transform: `translateY(${100 - topPercent}%)` }"
            />
        </div>
        <! -- Bottom module -->
        <div
            class="custombackground-b"
            :style="{ transform: `translateY(${100 - bottomPercent}%)` }"
        >
            <img
                :src="imgSrc"
                style="width: 100%;"
                :style="{ transform: `translateY(${bottomPercent - 100}%)` }"
            />
        </div>
    </div>
</template>
<script>
export default {
    name: 'CustomBackgroundImage'.props: {
        imgSrc: { // The actual background image url
            type: String.required: true
        },
        topPercent: { // The percentage of the header in the image
            type: Number.default: 50
        },
        bottomPercent: { // The bottom percentage of the image
            type: Number.default: 10}},data() {
        return {
            width: 0.// The actual width of the image
            height: 0.// The actual height of the image}},watch: {
        imgSrc: { // When the image URL changes, repull the actual width and height of the image in real time
            immediate: true.handler(val) {
                if (val) {
                    const i = new Image()
                    i.onload = (e) = > {
                        this.width = i.width
                        this.height = i.height
                        i.onload = null
                    }
                    i.src = val
                } else {
                    this.width = 0
                    this.height = 0}}}},computed: {
        imgRealHeight() { // Calculate the actual occupied height according to the actual occupied width (keep the image length ratio unchanged)
            const val = this.width && this.$refs.imgRef ? this.height * this.$refs.imgRef.clientWidth / this.width : 0
            return val
        },
        centerScale() { // Calculate the scaling ratio of the middle part
            if (!this.$refs.imgRef) {
                this.centerScale = 1
            } else {
                const allPercent = (this.topPercent + this.bottomPercent) / 100
                this.centerScale = (this.$refs.imgRef.clientHeight - this.imgRealHeight * allPercent) / (this.imgRealHeight * (1 - allPercent))
            }
        }
    },
}
</script>
<style>
.custombackground-t {
    overflow: hidden;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
}
.custombackground-b {
    overflow: hidden;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
}
.custombackground-c {
    overflow: hidden;
    position: absolute;
    left: 0;
    right: 0;
}
</style>
Copy the code

Preliminary ideas, welcome to discuss, to implement the background zoom function under high compatibility