swiper: CSS Grid + Swiper Wrapper - wrong width calculated

This is a (multiple allowed):

What you did

A basic CSS grid setup with 3 columns setup on a wrapper. Carousel is set up within the 3rd column with a width of 1fr (which should take up 1fr of the remaining space of the max-width container). For code example see codepen showing issue. Code is direct replica of code in my development build.

Expected Behavior

Swiper wrapper is to take up the remaining space of the container instead of overflowing with the correct slidesPerView visible

Actual Behavior

Swiper wrapper is overflowing, with slidersPerView being ignored. Wrapper is showing width of entire width of elements.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 33
  • Comments: 42 (2 by maintainers)

Commits related to this issue

Most upvoted comments

I had a similar issue and found a solution.

You can prevent Swiper from overflowing by adding an overflow: hidden to the parent element (in your case the .wrapper).

And there was also an issue with your grid column setup. .sidebar should have a value of 1 / 2 and .carousel a value of 2 / 3.

I updated your Codepen example: https://codepen.io/anon/pen/MdmxNp

instead of ‘auto’ in grid-column definition, you can use ‘minmax(0, auto)’. the column width gets calculated in pixel, so the swiper calculates its width correctly.

One more workaround to add, as I’ve noticed something specific. If I have a 2-column grid (using grid-template-columns: 1fr 1fr), the crucial part is that the immediate child in the column must have overflow: hidden. Then, Swiper will calculate its width correctly no matter how far nested it is.

  • container (grid, two columns)
    • div (100% width, overflow hidden)
      • div
        • div
          • swiper

If the immediate child of the column is not set to overflow hidden, the width won’t be calculated correctly

This will break:

  • container (grid, two columns)
    • div
      • div
        • div (100% width, overflow hidden)
          • swiper

Right now solution is using minmax(0, 1fr) instead of 1fr.

My workaround to solve this problem for a single-slide slider that placed inside flex item.

.swiper-slide {
    width: 100% !important;
}

Tested in Swiper 6.4.8

For me, it worked to wrap the slider with an additional display: grid element and set swiper-container to 100% width. codepen as demo: https://codepen.io/_Mellow/pen/KKmRwzw

At the very least, there should be a “Gotchas” section, or something to that effect added to the documentation that notes this blatant issue. I can imagine many people, like myself, pulled their hair out for far, far too long thinking something was wrong with our setup.

In my case, it was a basic flex layout. Adding overflow: hidden to the parent did fix the issue immediately.

Still happening… Swiper goes bonkers if it’s in a Grid with FR units.

When changing grid-template-columns to percentage instead fr, it works, but makes the “grid gaps” calculation more tedious this way.

Almost a year later and grid is a best practice. It would really help if this issue would not exist anymore. 😃

The fix from https://github.com/nolimits4web/swiper/issues/2914#issuecomment-493384617 worked like a charm nonetheless!

And of course, thank you for swiper, it works really well, and kudos for the good docs!

I got the same issue and the overflow: hidden trick doesn’t work. I think the problem is similar to what @suxscribe described. I set the layout using fr, not px.

This is my screenshot: https://prnt.sc/ry8y59

Just to contribute to the catalog of workarounds: in my case I was using only a single column in the grid, so I instead of using the default value for grid-template-columns, I explicitly set it to grid-template-columns: 100%; and it worked wonders, thank you guys 😉

wasted hours until found the display grid on parent was growing swiper width and some times height to infinity. Used this to fix it but feels scared what if people get that bug in their browser or device for whatever reason

display: grid; grid-template-columns: minmax(0, 1fr);

I had a similar issue and found a solution.

You can prevent Swiper from overflowing by adding an overflow: hidden to the parent element (in your case the .wrapper).

And there was also an issue with your grid column setup. .sidebar should have a value of 1 / 2 and .carousel a value of 2 / 3.

I updated your Codepen example: https://codepen.io/anon/pen/MdmxNp

Your solution only works if you set width of some column in ‘px’. If columns are set in ‘fr’ swiper takes all the space and goes into infinity (I have 6-digit numbers in ‘translate3d’ property of the slides)

In such layout, there is no clear way in this case to detect available “cell” width -> so swiper can’t calculate its own and slides size. You can fix this current layout but changing width: 100vw on .carousel or by using flex instead of grid

I had this problem on iOS 12 but overflow: hidden wasn’t enough.

So, in place of this grid-template-columns: 6fr 6fr;

I used this grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);

and it worked.

One more workaround to add, as I’ve noticed something specific. If I have a 2-column grid (using grid-template-columns: 1fr 1fr), the crucial part is that the immediate child in the column must have overflow: hidden. Then, Swiper will calculate its width correctly no matter how far nested it is.

  • container (grid, two columns)

    • div (100% width, overflow hidden)

      • div

        • div

          • swiper

If the immediate child of the column is not set to overflow hidden, the width won’t be calculated correctly

This will break:

  • container (grid, two columns)

    • div

      • div

        • div (100% width, overflow hidden)

          • swiper

This is the one that fixes swiper slider from making wrong calculations in the order of exponents.

Very helpful content here, thanks! Adding my case here if anyone will have sth similar

<Grid> // grid-template-areas set, display grid
  <GridArea1> // grid-area set, display block. contains Swiper
    <Swiper />
  </GridArea1>
  <GridArea2 /> // grid-area set, display block
  <GridArea3 /> // grid-area set, display block
</Grid>

The solution was to add this to GridArea1 styles - the element is a block itself, but is a part of the grid:

min-width: 0;

Was able to come up with this after reading this StackOverflow answer.

I had 2 different scenarios, both kind of relating to what I raised in #4993

Scenario 1

Parent element with display grid and 1 column. Swiper deep nested inside of it.

.parent {
  display: grid;
  grid-template-rows: 16px;
}

The problem here across all browsers was that swiper didn’t calculate the width properly so each slide was causing a horizontal scroll by pushing the container. To solve it I also added grid-template-columns: 100%; to the .parent.

Another fix I did for this before was to wrap swiper in another grid and that seemed to do the trick. But that has an issue that I will explain bellow.

Scenario 2

Parent element with display grid and multiple columns. Swiper nested 2 levels down in the .col element.

.parent {
  display: grid;
  grid-template-rows: repeat(var(--rows, 1), 1fr);
  grid-template-columns: repeat(var(--columns, 12), 1fr);
  gap: var(--gap, 16px);
}

.parent .col {
  grid-column: auto/span 6;
}

In this case Chrome is fine, but on Firefox Swiper will grow to infinity without stoping. To fix this I had to change the template columns to grid-template-columns: repeat(var(--columns, 12), minmax(0, 1fr));.

Initially to solve this issue was to disable the resize observer in settings. Seems that the observer triggers all the time.

Works for me like this:

/** @jsx jsx */
import { jsx, Grid } from '@chakra-ui/core';
import Swiper from 'react-id-swiper';

function CarouselGrid() {

    const params = {
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    }

    return (
      <Grid gridTemplateColumns="1fr 3fr">
        <div>
          Col Left
        </div>
        <div sx={{ width: '100%', overflow: 'hidden'}}>
          <div sx={{
            '.swiper-container': {
              width: '100%'
            }
          }}>
            <Swiper {...params}>
              <div sx={{ bg: 'gold' }}>Slide #1</div>
              <div sx={{ bg: 'red' }}>Slide #2</div>
            </Swiper>
          </div>
        </div>
      </Grid>
    )
  }

Have there been any other fixes? This thread was created on Swiper 4.2.2, but I’m getting similar painful behavior with SwiperJS v6.1.2 & CSS Grid.

In some scenarios, Swiper disregards the grid (as if it has been absolutely positioned). In some scenarios, Swiper will not resize responsively (i.e,. always the max-width of the grid child it’s in), even within a breakpoint. Setting overflow:hidden does not fix the issue, and unluckily, we are tied to the fr units. It’s one of grid’s by-design features to automatically calculate the viewport in fractional units.

I wish we could use flexbox in our layout, but the site is quite deeply integrated in grid. I agree with @ckihneman: if CSS grid incompatibilities are present in the stable release, it should be noted somewhere in the documentation. Grid is a first-class citizen of CSS, at least since early 2017.

The only reliable solution I’ve found: very carefully limiting the nesting of any SwiperJS element, even divs with zero CSS set. I can get, at most, exactly grid -> grid child -> swiper element. Anything more destroys the layout.