【问题标题】:Multiple divs go out of bounds even though there's no rules that should make it do so多个 div 超出范围,即使没有规则可以这样做
【发布时间】:2021-11-27 12:13:28
【问题描述】:

我有这个相当原始的幻灯片,但由于某种原因,CSS 搞砸了。 flex-container 和 carousel-container 似乎比原始图像大,不应该是这样。我做错了什么?

class CarouselController {

    defaultSettings = {
        loop: true,
        delay: 3000,
        autoplay: true
    }

    /**
     * @@param {object} settings
     */
    constructor(settings) {
        this.carousel = settings.element;
        delete settings.element;

        this.current = 0;
        this.hooks = {};
        this.settings = settings;

        if (!this.carousel) {
            throw 'A carousel element is required. For example: new CarouselController({ element: document.getElementById(\'carousel\') })';
        }

        /**
         * Sanitize `loop` setting
         */
        this.addFilter('setting.loop', value => {
            return String(value).toLowerCase() === 'true';
        });

        /**
         * Sanitize `delay` setting
         */
        this.addFilter('setting.delay', value => parseInt(value));

        /**
         * Sanitize `autoplay` setting
         */
        this.addFilter('setting.autoplay', value => {
            return String(value).toLowerCase() === 'true';
        });

        // Autoplay on init.
        if (this.getSetting('autoplay')) {
            this.play();
        }
    }

    /**
     * Get the carousel container element.
     * @@returns {Element}
     */
    getCarousel() {
        return this.carousel;
    }

    /**
     * Get a setting value.
     * @@param {string} name
     * @@param defaultValue
     * @@returns {*}
     */
    getSetting(name, defaultValue) {
        if (!defaultValue && name in this.defaultSettings) {
            defaultValue = this.defaultSettings[name]
        }

        /**
         * Apply value filters.
         * @@example carousel.addFilter('setting.delay', function(value) { return value + 500; });
         */
        return this.applyFilters(`setting.${name}`, name in this.settings ? this.settings[name] : defaultValue);
    }

    /**
     * Get hooks by type and name. Ordered by priority.
     * @@param {string} type
     * @@param {string} name
     * @@returns {array}
     */
    getHooks(type, name) {
        let hooks = [];

        if (type in this.hooks) {
            let localHooks = this.hooks[type];
            localHooks = localHooks.filter(el => el.name === name);
            localHooks = localHooks.sort((a, b) => a.priority - b.priority);
            hooks = hooks.concat(localHooks);
        }

        return hooks;
    }

    /**
     * Add a hook.
     * @@param {string} type
     * @@param {object} hookMeta
     */
    addHook(type, hookMeta) {

        // Create new local hook type array.
        if (!(type in this.hooks)) {
            this.hooks[type] = [];
        }

        this.hooks[type].push(hookMeta);
    }

    /**
     * Add action listener.
     * @@param {string} action Name of action to trigger callback on.
     * @@param {function} callback
     * @@param {number} priority
     */
    addAction(action, callback, priority = 10) {
        this.addHook('actions', {
            name: action,
            callback: callback,
            priority: priority
        });
    }

    /**
     * Trigger an action.
     * @@param {string} name Name of action to run.
     * @@param {*} args Arguments passed to the callback function.
     */
    doAction(name, ...args) {
        this.getHooks('actions', name).forEach(hook => {
           hook.callback(...args);
        });
    }

    /**
     * Register filter.
     * @@param {string} filter Name of filter to trigger callback on.
     * @@param {function} callback
     * @@param {number} priority
     */
    addFilter(filter, callback, priority = 10) {
        this.addHook('filters', {
            name: filter,
            callback: callback,
            priority: priority
        });
    }

    /**
     * Apply all named filters to a value.
     * @@param {string} name Name of action to run.
     * @@param {*} value The value to be mutated.
     * @@param {*} args Arguments passed to the callback function.
     * @@returns {*}
     */
    applyFilters(name, value, ...args) {
        this.getHooks('filters', name).forEach(hook => {
            value = hook.callback(value, ...args);
        });

        return value;
    }

    /**
     * Get all the children (slides) elements.
     * @@returns {Element[]}
     */
    getSlides() {
        return Array.from(this.getCarousel().children);
    }

    /**
     * Get a specific slide by index.
     * @@param {int} index
     * @@returns {Element|null}
     */
    getSlide(index) {
        return this.getSlides()[index];
    }

    /**
     * Show a specific slide by index.
     * @@param {int} index
     * @@returns {int}
     */
    goTo(index) {
        const slides = this.getSlides();
        const slide = this.getSlide(index);

        if (slide) {
            slides.forEach((el) => {
                el.classList.remove('active');
            });

            slide.classList.add('active');

            this.current = slides.indexOf(slide);

            /**
             * Trigger goto event.
             * @@example carousel.addAction('goto', function(slide, index) { ... });
             */
            this.doAction('goto', slide, this.current);
        }

        return this.current;
    }

    /**
     * Show the next slide (if has one).
     */
    next() {
        let replay = false;

        // Check if carousel is looping through slides automatically.
        if (this.playing) {
            replay = true;
        }

        const slides = this.getSlides();
        let nextIndex = this.current + 1;

        // If the next slide is greater than the total, reset to 0 if looping else use -1 to stop `goTo` method.
        if (nextIndex > (slides.length - 1)) {
            if (this.getSetting('loop')) {
                nextIndex = 0;
            } else {
                nextIndex = -1;
            }
        }

        // Only go to slide if next index is valid.
        if (nextIndex >= 0) {
            this.goTo(nextIndex);

            // Continue with auto play.
            if (replay) {
                this.play();
            }
        }
    }

    /**
     * Show the previous slide (if has one).
     */
    previous() {
        let replay = false;

        // Check if carousel is looping through slides automatically.
        if (this.playing) {
            replay = true;
        }

        const slides = this.getSlides();
        let prevIndex = this.current - 1;

        // If the prev slide is less than 0, reset to the last slide if looping else use -1 to stop `goTo` method.
        if (prevIndex < 0) {
            if (this.getSetting('loop')) {
                prevIndex = slides.length - 1;
            } else {
                prevIndex = -1;
            }
        }

        // Only go to slide if next index is valid.
        if (prevIndex >= 0) {
            this.goTo(prevIndex);

            // Continue with auto play.
            if (replay) {
                this.play();
            }
        }
    }

    /**
     * Automatically go to the next slide (or start if loop is true).
     * @@returns {number}
     */
    play() {
        this.stop();

        this.goTo(this.current);

        this.playing = setInterval(() => {
            this.next();
        }, this.getSetting('delay'));

        return this.playing;
    }

    /**
     * Stop the automatic carousel if running.
     */
    stop() {
        if (this.playing) {
            clearInterval(this.playing);
        }
    }


}

/**
 * Get the carousel container element.
 * @@type {Element}
 */
const carouselContainer = document.querySelector('.carousel-container');

/**
 * Create a new controller instance for our carousel.
 * @@type {CarouselController}
 */
const carousel = new CarouselController({
    element: carouselContainer.querySelector('.carousel'),
    loop: true,
    delay: 3000,
    autoplay: true
});

/**
 * Lazy load each image only when the slide is in view.
 */
carousel.addAction('goto', function(slide, index) {
    let images = [];

    if (slide.tagName.toLowerCase() === 'img') {
        images.push(slide);
    } else {
        images.concat(slide.querySelectorAll('img'));
    }

    images.forEach((img) => {
        if (!img.src && img.dataset.src) {
            img.src = img.dataset.src;
        }
    });
});
:root {
    --carousel-width: 70vw;
    /*--carousel-height: calc(calc(calc(9 / 16) * var(--carousel-width)));*/
    --carousel-height: 70vh;
}

.carousel {
  width: var(--carousel-width);
  height: var(--carousel-height);
  contain: strict;
  margin-top: 1vw;
  border-radius: 3vmin;
  max-height: 1000px;
  max-width: 1000px;
}
/* Hide all carousel slides by default */
.carousel-container .carousel > * {
  display: none;
}

/* Only show the active carousel slide */
.carousel-container .carousel > *.active {
  display: block;
}

.carousel-container {
    width: auto;
    height: auto;
    max-height: 50vh;
}
.flex-container {
    display: inline-flex;
    flex-flow: row wrap;
    position: relative;
}
<div class="carousel-container">
  <div class="flex-container">
    <div class="carousel">

      <img data-src="https://picsum.photos/500/300" src="https://picsum.photos/500/300" />
      <img loading="lazy" data-src="https://picsum.photos/500/300" />
      <img loading="lazy" data-src="https://picsum.photos/500/300" />
      <img loading="lazy" data-src="https://picsum.photos/500/300" />
      <img loading="lazy" data-src="https://picsum.photos/500/300" />
      <img loading="lazy" data-src="https://picsum.photos/500/300" />
    </div>
  </div>
</div>

轮播的高度和宽度有这两个变量,但如果我将它们更改为除此之外的任何其他值或类似的vh / vw 值,图片就会消失。这也很奇怪。

【问题讨论】:

    标签: javascript html css flexbox


    【解决方案1】:

    flex-container 和 carousel-container 似乎比原始图像大

    添加display:flex 将使carousel-container 与子元素对齐宽度。此外,由于max-height: 50vh;,高度将受到限制。删除 max-height: 50vh; 以得到高度和宽度的精确匹配。

    .carousel-container {
        width: auto;
        height: auto;
        max-height: 50vh;
        display: flex;
    }
    

    widthheight 更新为100%auto 使其成为动态的并且不依赖于视口。

    .carousel {
        width: 100%;
        height: 100%;
        margin-top: 1vw;
        border-radius: 3vmin;
        max-height: 1000px;
        max-width: 1000px;
    }
    

    同时将contain:strict; 删除为

    只有在高度和宽度已知且固定时才使用contain:strict;

    .carousel {
        width: 500px;
        height: 300px;
        contain: strict;
        margin-top: 1vw;
        border-radius: 3vmin;
        max-height: 1000px;
        max-width: 1000px;
    }
    

    带有contain:strict 的片段:

    class CarouselController {
    
        defaultSettings = {
            loop: true,
            delay: 3000,
            autoplay: true
        }
    
        /**
         * @@param {object} settings
         */
        constructor(settings) {
            this.carousel = settings.element;
            delete settings.element;
    
            this.current = 0;
            this.hooks = {};
            this.settings = settings;
    
            if (!this.carousel) {
                throw 'A carousel element is required. For example: new CarouselController({ element: document.getElementById(\'carousel\') })';
            }
    
            /**
             * Sanitize `loop` setting
             */
            this.addFilter('setting.loop', value => {
                return String(value).toLowerCase() === 'true';
            });
    
            /**
             * Sanitize `delay` setting
             */
            this.addFilter('setting.delay', value => parseInt(value));
    
            /**
             * Sanitize `autoplay` setting
             */
            this.addFilter('setting.autoplay', value => {
                return String(value).toLowerCase() === 'true';
            });
    
            // Autoplay on init.
            if (this.getSetting('autoplay')) {
                this.play();
            }
        }
    
        /**
         * Get the carousel container element.
         * @@returns {Element}
         */
        getCarousel() {
            return this.carousel;
        }
    
        /**
         * Get a setting value.
         * @@param {string} name
         * @@param defaultValue
         * @@returns {*}
         */
        getSetting(name, defaultValue) {
            if (!defaultValue && name in this.defaultSettings) {
                defaultValue = this.defaultSettings[name]
            }
    
            /**
             * Apply value filters.
             * @@example carousel.addFilter('setting.delay', function(value) { return value + 500; });
             */
            return this.applyFilters(`setting.${name}`, name in this.settings ? this.settings[name] : defaultValue);
        }
    
        /**
         * Get hooks by type and name. Ordered by priority.
         * @@param {string} type
         * @@param {string} name
         * @@returns {array}
         */
        getHooks(type, name) {
            let hooks = [];
    
            if (type in this.hooks) {
                let localHooks = this.hooks[type];
                localHooks = localHooks.filter(el => el.name === name);
                localHooks = localHooks.sort((a, b) => a.priority - b.priority);
                hooks = hooks.concat(localHooks);
            }
    
            return hooks;
        }
    
        /**
         * Add a hook.
         * @@param {string} type
         * @@param {object} hookMeta
         */
        addHook(type, hookMeta) {
    
            // Create new local hook type array.
            if (!(type in this.hooks)) {
                this.hooks[type] = [];
            }
    
            this.hooks[type].push(hookMeta);
        }
    
        /**
         * Add action listener.
         * @@param {string} action Name of action to trigger callback on.
         * @@param {function} callback
         * @@param {number} priority
         */
        addAction(action, callback, priority = 10) {
            this.addHook('actions', {
                name: action,
                callback: callback,
                priority: priority
            });
        }
    
        /**
         * Trigger an action.
         * @@param {string} name Name of action to run.
         * @@param {*} args Arguments passed to the callback function.
         */
        doAction(name, ...args) {
            this.getHooks('actions', name).forEach(hook => {
               hook.callback(...args);
            });
        }
    
        /**
         * Register filter.
         * @@param {string} filter Name of filter to trigger callback on.
         * @@param {function} callback
         * @@param {number} priority
         */
        addFilter(filter, callback, priority = 10) {
            this.addHook('filters', {
                name: filter,
                callback: callback,
                priority: priority
            });
        }
    
        /**
         * Apply all named filters to a value.
         * @@param {string} name Name of action to run.
         * @@param {*} value The value to be mutated.
         * @@param {*} args Arguments passed to the callback function.
         * @@returns {*}
         */
        applyFilters(name, value, ...args) {
            this.getHooks('filters', name).forEach(hook => {
                value = hook.callback(value, ...args);
            });
    
            return value;
        }
    
        /**
         * Get all the children (slides) elements.
         * @@returns {Element[]}
         */
        getSlides() {
            return Array.from(this.getCarousel().children);
        }
    
        /**
         * Get a specific slide by index.
         * @@param {int} index
         * @@returns {Element|null}
         */
        getSlide(index) {
            return this.getSlides()[index];
        }
    
        /**
         * Show a specific slide by index.
         * @@param {int} index
         * @@returns {int}
         */
        goTo(index) {
            const slides = this.getSlides();
            const slide = this.getSlide(index);
    
            if (slide) {
                slides.forEach((el) => {
                    el.classList.remove('active');
                });
    
                slide.classList.add('active');
    
                this.current = slides.indexOf(slide);
    
                /**
                 * Trigger goto event.
                 * @@example carousel.addAction('goto', function(slide, index) { ... });
                 */
                this.doAction('goto', slide, this.current);
            }
    
            return this.current;
        }
    
        /**
         * Show the next slide (if has one).
         */
        next() {
            let replay = false;
    
            // Check if carousel is looping through slides automatically.
            if (this.playing) {
                replay = true;
            }
    
            const slides = this.getSlides();
            let nextIndex = this.current + 1;
    
            // If the next slide is greater than the total, reset to 0 if looping else use -1 to stop `goTo` method.
            if (nextIndex > (slides.length - 1)) {
                if (this.getSetting('loop')) {
                    nextIndex = 0;
                } else {
                    nextIndex = -1;
                }
            }
    
            // Only go to slide if next index is valid.
            if (nextIndex >= 0) {
                this.goTo(nextIndex);
    
                // Continue with auto play.
                if (replay) {
                    this.play();
                }
            }
        }
    
        /**
         * Show the previous slide (if has one).
         */
        previous() {
            let replay = false;
    
            // Check if carousel is looping through slides automatically.
            if (this.playing) {
                replay = true;
            }
    
            const slides = this.getSlides();
            let prevIndex = this.current - 1;
    
            // If the prev slide is less than 0, reset to the last slide if looping else use -1 to stop `goTo` method.
            if (prevIndex < 0) {
                if (this.getSetting('loop')) {
                    prevIndex = slides.length - 1;
                } else {
                    prevIndex = -1;
                }
            }
    
            // Only go to slide if next index is valid.
            if (prevIndex >= 0) {
                this.goTo(prevIndex);
    
                // Continue with auto play.
                if (replay) {
                    this.play();
                }
            }
        }
    
        /**
         * Automatically go to the next slide (or start if loop is true).
         * @@returns {number}
         */
        play() {
            this.stop();
    
            this.goTo(this.current);
    
            this.playing = setInterval(() => {
                this.next();
            }, this.getSetting('delay'));
    
            return this.playing;
        }
    
        /**
         * Stop the automatic carousel if running.
         */
        stop() {
            if (this.playing) {
                clearInterval(this.playing);
            }
        }
    
    
    }
    
    /**
     * Get the carousel container element.
     * @@type {Element}
     */
    const carouselContainer = document.querySelector('.carousel-container');
    
    /**
     * Create a new controller instance for our carousel.
     * @@type {CarouselController}
     */
    const carousel = new CarouselController({
        element: carouselContainer.querySelector('.carousel'),
        loop: true,
        delay: 3000,
        autoplay: true
    });
    
    /**
     * Lazy load each image only when the slide is in view.
     */
    carousel.addAction('goto', function(slide, index) {
        let images = [];
    
        if (slide.tagName.toLowerCase() === 'img') {
            images.push(slide);
        } else {
            images.concat(slide.querySelectorAll('img'));
        }
    
        images.forEach((img) => {
            if (!img.src && img.dataset.src) {
                img.src = img.dataset.src;
            }
        });
    });
    :root {
        --carousel-width: 70vw;
        /*--carousel-height: calc(calc(calc(9 / 16) * var(--carousel-width)));*/
        --carousel-height: 70vh;
    }
    
    .carousel {
      width: 500px;
      height: 300px;
      contain: strict;
      margin-top: 1vw;
      border-radius: 3vmin;
      max-height: 1000px;
      max-width: 1000px;
    }
    /* Hide all carousel slides by default */
    .carousel-container .carousel > * {
      display: none;
    }
    
    /* Only show the active carousel slide */
    .carousel-container .carousel > *.active {
      display: block;
    }
    
    .carousel-container {
        width: auto;
        height: auto;
        max-height: 50vh;
        display: flex;
    }
    .flex-container {
        display: inline-flex;
        flex-flow: row wrap;
        position: relative;
    }
    <div class="carousel-container">
      <div class="flex-container">
        <div class="carousel">
    
          <img data-src="https://picsum.photos/500/300" src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
        </div>
      </div>
    </div>

    不带contain:strict 的片段:

    class CarouselController {
    
        defaultSettings = {
            loop: true,
            delay: 3000,
            autoplay: true
        }
    
        /**
         * @@param {object} settings
         */
        constructor(settings) {
            this.carousel = settings.element;
            delete settings.element;
    
            this.current = 0;
            this.hooks = {};
            this.settings = settings;
    
            if (!this.carousel) {
                throw 'A carousel element is required. For example: new CarouselController({ element: document.getElementById(\'carousel\') })';
            }
    
            /**
             * Sanitize `loop` setting
             */
            this.addFilter('setting.loop', value => {
                return String(value).toLowerCase() === 'true';
            });
    
            /**
             * Sanitize `delay` setting
             */
            this.addFilter('setting.delay', value => parseInt(value));
    
            /**
             * Sanitize `autoplay` setting
             */
            this.addFilter('setting.autoplay', value => {
                return String(value).toLowerCase() === 'true';
            });
    
            // Autoplay on init.
            if (this.getSetting('autoplay')) {
                this.play();
            }
        }
    
        /**
         * Get the carousel container element.
         * @@returns {Element}
         */
        getCarousel() {
            return this.carousel;
        }
    
        /**
         * Get a setting value.
         * @@param {string} name
         * @@param defaultValue
         * @@returns {*}
         */
        getSetting(name, defaultValue) {
            if (!defaultValue && name in this.defaultSettings) {
                defaultValue = this.defaultSettings[name]
            }
    
            /**
             * Apply value filters.
             * @@example carousel.addFilter('setting.delay', function(value) { return value + 500; });
             */
            return this.applyFilters(`setting.${name}`, name in this.settings ? this.settings[name] : defaultValue);
        }
    
        /**
         * Get hooks by type and name. Ordered by priority.
         * @@param {string} type
         * @@param {string} name
         * @@returns {array}
         */
        getHooks(type, name) {
            let hooks = [];
    
            if (type in this.hooks) {
                let localHooks = this.hooks[type];
                localHooks = localHooks.filter(el => el.name === name);
                localHooks = localHooks.sort((a, b) => a.priority - b.priority);
                hooks = hooks.concat(localHooks);
            }
    
            return hooks;
        }
    
        /**
         * Add a hook.
         * @@param {string} type
         * @@param {object} hookMeta
         */
        addHook(type, hookMeta) {
    
            // Create new local hook type array.
            if (!(type in this.hooks)) {
                this.hooks[type] = [];
            }
    
            this.hooks[type].push(hookMeta);
        }
    
        /**
         * Add action listener.
         * @@param {string} action Name of action to trigger callback on.
         * @@param {function} callback
         * @@param {number} priority
         */
        addAction(action, callback, priority = 10) {
            this.addHook('actions', {
                name: action,
                callback: callback,
                priority: priority
            });
        }
    
        /**
         * Trigger an action.
         * @@param {string} name Name of action to run.
         * @@param {*} args Arguments passed to the callback function.
         */
        doAction(name, ...args) {
            this.getHooks('actions', name).forEach(hook => {
               hook.callback(...args);
            });
        }
    
        /**
         * Register filter.
         * @@param {string} filter Name of filter to trigger callback on.
         * @@param {function} callback
         * @@param {number} priority
         */
        addFilter(filter, callback, priority = 10) {
            this.addHook('filters', {
                name: filter,
                callback: callback,
                priority: priority
            });
        }
    
        /**
         * Apply all named filters to a value.
         * @@param {string} name Name of action to run.
         * @@param {*} value The value to be mutated.
         * @@param {*} args Arguments passed to the callback function.
         * @@returns {*}
         */
        applyFilters(name, value, ...args) {
            this.getHooks('filters', name).forEach(hook => {
                value = hook.callback(value, ...args);
            });
    
            return value;
        }
    
        /**
         * Get all the children (slides) elements.
         * @@returns {Element[]}
         */
        getSlides() {
            return Array.from(this.getCarousel().children);
        }
    
        /**
         * Get a specific slide by index.
         * @@param {int} index
         * @@returns {Element|null}
         */
        getSlide(index) {
            return this.getSlides()[index];
        }
    
        /**
         * Show a specific slide by index.
         * @@param {int} index
         * @@returns {int}
         */
        goTo(index) {
            const slides = this.getSlides();
            const slide = this.getSlide(index);
    
            if (slide) {
                slides.forEach((el) => {
                    el.classList.remove('active');
                });
    
                slide.classList.add('active');
    
                this.current = slides.indexOf(slide);
    
                /**
                 * Trigger goto event.
                 * @@example carousel.addAction('goto', function(slide, index) { ... });
                 */
                this.doAction('goto', slide, this.current);
            }
    
            return this.current;
        }
    
        /**
         * Show the next slide (if has one).
         */
        next() {
            let replay = false;
    
            // Check if carousel is looping through slides automatically.
            if (this.playing) {
                replay = true;
            }
    
            const slides = this.getSlides();
            let nextIndex = this.current + 1;
    
            // If the next slide is greater than the total, reset to 0 if looping else use -1 to stop `goTo` method.
            if (nextIndex > (slides.length - 1)) {
                if (this.getSetting('loop')) {
                    nextIndex = 0;
                } else {
                    nextIndex = -1;
                }
            }
    
            // Only go to slide if next index is valid.
            if (nextIndex >= 0) {
                this.goTo(nextIndex);
    
                // Continue with auto play.
                if (replay) {
                    this.play();
                }
            }
        }
    
        /**
         * Show the previous slide (if has one).
         */
        previous() {
            let replay = false;
    
            // Check if carousel is looping through slides automatically.
            if (this.playing) {
                replay = true;
            }
    
            const slides = this.getSlides();
            let prevIndex = this.current - 1;
    
            // If the prev slide is less than 0, reset to the last slide if looping else use -1 to stop `goTo` method.
            if (prevIndex < 0) {
                if (this.getSetting('loop')) {
                    prevIndex = slides.length - 1;
                } else {
                    prevIndex = -1;
                }
            }
    
            // Only go to slide if next index is valid.
            if (prevIndex >= 0) {
                this.goTo(prevIndex);
    
                // Continue with auto play.
                if (replay) {
                    this.play();
                }
            }
        }
    
        /**
         * Automatically go to the next slide (or start if loop is true).
         * @@returns {number}
         */
        play() {
            this.stop();
    
            this.goTo(this.current);
    
            this.playing = setInterval(() => {
                this.next();
            }, this.getSetting('delay'));
    
            return this.playing;
        }
    
        /**
         * Stop the automatic carousel if running.
         */
        stop() {
            if (this.playing) {
                clearInterval(this.playing);
            }
        }
    
    
    }
    
    /**
     * Get the carousel container element.
     * @@type {Element}
     */
    const carouselContainer = document.querySelector('.carousel-container');
    
    /**
     * Create a new controller instance for our carousel.
     * @@type {CarouselController}
     */
    const carousel = new CarouselController({
        element: carouselContainer.querySelector('.carousel'),
        loop: true,
        delay: 3000,
        autoplay: true
    });
    
    /**
     * Lazy load each image only when the slide is in view.
     */
    carousel.addAction('goto', function(slide, index) {
        let images = [];
    
        if (slide.tagName.toLowerCase() === 'img') {
            images.push(slide);
        } else {
            images.concat(slide.querySelectorAll('img'));
        }
    
        images.forEach((img) => {
            if (!img.src && img.dataset.src) {
                img.src = img.dataset.src;
            }
        });
    });
    :root {
        --carousel-width: 70vw;
        /*--carousel-height: calc(calc(calc(9 / 16) * var(--carousel-width)));*/
        --carousel-height: 70vh;
    }
    
    .carousel {
      width: 100%;
      height: 100%;
      margin-top: 1vw;
      border-radius: 3vmin;
      max-height: 1000px;
      max-width: 1000px;
    }
    /* Hide all carousel slides by default */
    .carousel-container .carousel > * {
      display: none;
    }
    
    /* Only show the active carousel slide */
    .carousel-container .carousel > *.active {
      display: block;
    }
    
    .carousel-container {
        width: auto;
        height: auto;
        max-height: 50vh;
        display: flex;
    }
    .flex-container {
        display: inline-flex;
        flex-flow: row wrap;
        position: relative;
    }
    <div class="carousel-container">
      <div class="flex-container">
        <div class="carousel">
    
          <img data-src="https://picsum.photos/500/300" src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
          <img loading="lazy" data-src="https://picsum.photos/500/300" />
        </div>
      </div>
    </div>

    【讨论】:

    • 至少在 StackOverflow 中,carousel-container 与我的视口一样宽。不过,其他 div 现在似乎在界限内。任何线索如何解决它?
    • 没关系,在真正的实施工作中,我已经接受了你的回答 :-)
    • @Munchkin 嘿,如果它有效,那就太好了。 ^_^ 感谢您的接受和投票。
    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2017-11-30
    • 2016-03-14
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多