postcss / autoprefixer

Parse CSS and add vendor prefixes to rules by Can I Use
https://twitter.com/autoprefixer
MIT License
21.66k stars 1.26k forks source link

grid-row-span and grid-column-span not being prefixed by autoprefixer #1063

Closed franktopel closed 6 years ago

franktopel commented 6 years ago

I have this SCSS mixin which creates css rules:

$columns: 12;
$rows: 12;

@mixin colspan-x {
    @for $i from 1 through $columns {
      .colspan#{$i} { grid-column-span: $i; }
    }
  }

  @mixin rowspan-x {
    @for $i from 1 through $rows {
      .rowspan#{$i} { grid-row-span: $i; }
    }
  }

@include colspan-x;
@include rowspan-x;

This creates

.colspan1 {
  grid-column-span: 1;
}

.colspan2 {
  grid-column-span: 2;
}

.colspan3 {
  grid-column-span: 3;
}

.colspan4 {
  grid-column-span: 4;
}

.colspan5 {
  grid-column-span: 5;
}

.colspan6 {
  grid-column-span: 6;
}

.colspan7 {
  grid-column-span: 7;
}

.colspan8 {
  grid-column-span: 8;
}

.colspan9 {
  grid-column-span: 9;
}

.colspan10 {
  grid-column-span: 10;
}

.colspan11 {
  grid-column-span: 11;
}

.colspan12 {
  grid-column-span: 12;
}

.rowspan1 {
  grid-row-span: 1;
}

.rowspan2 {
  grid-row-span: 2;
}

.rowspan3 {
  grid-row-span: 3;
}

.rowspan4 {
  grid-row-span: 4;
}

.rowspan5 {
  grid-row-span: 5;
}

.rowspan6 {
  grid-row-span: 6;
}

.rowspan7 {
  grid-row-span: 7;
}

.rowspan8 {
  grid-row-span: 8;
}

.rowspan9 {
  grid-row-span: 9;
}

.rowspan10 {
  grid-row-span: 10;
}

.rowspan11 {
  grid-row-span: 11;
}

.rowspan12 {
  grid-row-span: 12;
}

If I put this through autoprefixer (grid: true) the output stays identical, no -ms-grid-column-span and -ms-grid-row-span properties are being added. Other properties like grid-column and grid-row are properly prefixed.

ai commented 6 years ago

Check Autoprefixer warning. Grid support is limited and requires some additional properties.

How do you run Autopeprefixer?

franktopel commented 6 years ago

Autoprefixer is being run as a part of the new @vue/cli https://cli.vuejs.org/guide/css.html#postcss build process. I get the same result on https://autoprefixer.github.io/ as well.

I don't get to see any autoprefixer warning. You have an example that is guaranteed to issue a warning so I can check whether the warnings are hidden by the vue build process?

ai commented 6 years ago

Try this code from tests:

.warn {
    grid-column-end: 3;
    grid: subgrid;
    grid-template-areas: "head head"
                         "nav  main"
                         "foot ....";
}

Maybe we need to create a issue in Vue PostCSS runner to support warning.

franktopel commented 6 years ago

No warnings on the terminal I run the dev server in.

This is being created in my vue demo project:

.warn {
  -ms-grid-column-span: 3;
  grid-column-end: 3;
  grid: subgrid;
  grid-template-areas: "head head" "nav  main" "foot ....";
}

This is created by https://autoprefixer.github.io/ using last 1 version, ie <= 11 as a filter:

.warn {
    grid-column-end: 3;
    grid: subgrid;
        grid-template-areas: "head head"
                         "nav  main"
                         "foot ....";
}
ai commented 6 years ago

Can I ask you to create an issue in related Vue project (sorry, I have no idea where to create it). Mention me there, I will come and describe details.

Unfortunately, https://autoprefixer.github.io/ is not an official website to run Autoprefixer. It has many small issues :D.

franktopel commented 6 years ago

This is leading away from the original problem. Please put

.a { grid-row-span: 4; }
.b { grid-col-span: 4; }

in your tests.

ai commented 6 years ago

This is leading away from the original problem.

Try postcss-cli it will show you a warning (sorry, I am on vacation, can’t say what you need to fix in grid)

franktopel commented 6 years ago

I know the css grid has been an ongoing topic for a long time, but in our company we're going to have a grand meeting tomorrow in which we are to decide whether to use standard based CSS and rely on autoprefixer or whether to continue generating css rules in Javascript for IE 11. I'd love to say "we can rely on autoprefixer". The application this is used for is a huge application - they are creating a web based client instead of the Swing client they used to have up until now. This application has more than 3600 different masks, so the only solution to transfer it into a web interface is a generative approach. They used grid-based layout in the swing client before, so they are able to generate the proper CSS-grid-based html.

franktopel commented 6 years ago

This is what postcss-cli generates from a.css

.a { grid-row-span: 4; }
.b { grid-col-span: 4; }
@connexo > postcss a.css -o b.css
.a { grid-row-span: 4; }
.b { grid-col-span: 4; }
ai commented 6 years ago

If you want to run Autoprefixer on your existed CSS — it i bad idea. You must create grids from the beginning with Autoprefixer limits in the minds (this is why this feature is under the flag).

Also, grid by classes (like colspan1) is a bad idea. Grid layout has very useful grid-template feature. And we created Grid feature in Autoprefixer by looking to this way of using it. I really recommend describing styles in CSS, not in HTML by classes.

So, Autoprefixer grids are not “out of box” feature. You will need to learn how to use it (article about it will be posted in the middle of July by @Dan503).

ai commented 6 years ago

@franktopel show me your postcss.config.js which you used in postcss-cli

franktopel commented 6 years ago

I did not configure any, I just installed postcss-cli and autoprefixer globally. Where do I put it and what do I put in it for testing?

ai commented 6 years ago

@franktopel you must set grid: true option. So you must create postcss.config.js (in the same dir, where you put a.css):

module.exports = {
  plugins: [
    require('autoprefixer')({ grid: true })
  ]
}
franktopel commented 6 years ago

I really recommend describing styles in CSS, not in HTML by classes. I agree under normal circumstances, but I cannot agree in this case with the desribed "layout must be created using generation process" case.

franktopel commented 6 years ago

Using your config the result stays the same:

.a { grid-row-span: 4; }
.b { grid-col-span: 4; }
ai commented 6 years ago

If you want to create .colspan1, you don’t need an Autoprefixer. Just put -ms- properties manually to mixin. It is a single place, so you can describe all hacks there and then do not think about it.

franktopel commented 6 years ago

That might be a workaround, but question remains why are you not pre-fixing these basic properties? Is grid-col-span not properly prefixed when you generate -ms-grid-col-span?

ai commented 6 years ago

Wait a second. What is grid-row-span? I can’t find it in CSS grid spec

franktopel commented 6 years ago

https://css-tricks.com/almanac/properties/g/grid-row-column-span/

Warning: these properties have been removed from the spec. This removal was before stable versions of grid shipped in browsers, so they likely are not supported at all.

Hmm, how do we deal with this then?

Dan503 commented 6 years ago

Go with the IE version and auto prefixer.

I've got a three part series coming out in just 2 or 3 weeks that will teach you everything you need to know about using css-grid safely in IE.

The issue you are facing is that you are not specifying a start column or an end column. You can't just specify a span and leave it at that for Autoprefixer to work.

Here is the bit in the article about spanning multiple cells:


Autoprefixer has limited column and row spanning support

There is only one way to span multiple cells in IE. You need to define two things, a starting cell, and how many other cells you would like to span.

.grid-cell {
  -ms-grid-column: 1; /* starting cell */
  -ms-grid-column-span: 2; /* number of cells to span */
}

In modern browsers, you have access to far more options.

Autoprefixer friendly

Out of the modern ways to span multiple cells, Autoprefixer fully supports the following. Feel free to use any of these methods as much as you like:

Specify a starting line and the number of lines to span (similar to IE):

.grid-cell {
  grid-column: 1 / span 2;
}

Specify an end line and then span backwards:

.grid-cell {
  grid-column: span 2 / 3;
}

Specify a starting line and an end line directly:

.grid-cell {
  grid-column: 1 / 3;
}

Autoprefixer unfriendly. Here be dragons!

Now this is where Autoprefixer reaches its limit. The following methods are supported in modern browsers but are not supported by Autoprefixer. This is mainly due to Autoprefixer having no idea what grid the grid cell belongs to. For the last one, it is really only useful if you have access to auto-placement which is not something that IE supports.

Specify a starting line and how many lines from the end of the explicit grid to span:

.grid-cell {
  grid-column: 1 / -1;
}
/* also works in reverse */
.grid-cell {
  grid-column: -1 / 1;
}

Specify both the start and end line from the end of the explicit grid:

.grid-cell {
  grid-column: -3 / -1;
}

Specify only how many lines to span:

.grid-cell {
  grid-column: span 2;
}

So basically avoid using negative integers and don’t use purely just a span and you will be fine :)

franktopel commented 6 years ago

In the page I linked in my previous comment someone commented: https://css-tricks.com/almanac/properties/g/grid-row-column-span/#comment-1610564

Justin McDowell For the record, you can now accomplish this using the grid-column-end property instead:*

grid-column-end: span 3;

See it in action here: https://codepen.io/ragdoll/pen/mMbrNj

ai commented 6 years ago

This article is old and it says wrong things. The final Grid spec uses different syntax.

I will add warning for this case since this bad article can be popular.

Will you create a issue in Vue?

ai commented 6 years ago

Yeap grid-column-end should work (but I don't have my laptop right now to test).

franktopel commented 6 years ago

This is the JS snippet that has been used so far to create the grid classes:

var style = document.getElementById("css-grid").innerHTML;
var cols = 12;
var rows = 50;
var col;
for (col = 1; col < cols + 1; col++) {
                style = style + "\n.grid" + col + " { display: -ms-grid; -ms-grid-columns: (1fr)[" + col + "]; -ms-grid-rows: auto; }";
                style = style + "\n.col" + col + " { -ms-grid-column: " + col + "; }";
}
var row;
for (row = 1; row < rows + 1; row++) {
                style = style + "\n.row" + row + " { -ms-grid-row: " + row + "; }";
}
var colspan;
for (colspan = 1; colspan < cols + 1; colspan++) {
                style = style + "\n.colspan" + colspan + " { -ms-grid-column-span: "
                                               + colspan + "; }";
}
var rowspan;
for (rowspan = 1; rowspan < rows + 1; rowspan++) {
                style = style + "\n.rowspan" + rowspan + " { -ms-grid-row-span: "
                                               + rowspan + "; }";
}

And these are examples of how they generated their HTML:

<div class="col1 row1 colspan1 rowspan1">
  <div class="bm-header">
    Code-Table
  </div>
</div>

Unfortunately their generator also produces inline-styles:

<div class="bm-content-form" id="CodeTableHeaderContainer" style="display: -ms-grid; -ms-grid-rows: auto; -ms-grid-columns: 31fr 37fr 31fr">
franktopel commented 6 years ago

Will you create a issue in Vue?

For what? The postcss-cli doesn't issue a warning for this test case either.

YozhikM commented 6 years ago

@franktopel Here is a discussion. Including why you can not trust the authors of articles, especially older articles

ai commented 6 years ago

I think it is much better to use class like header in HTML and describe position of element in CSS by grid-template-areas. Describing position by classes is bad since it doesn't work good with media queries.

franktopel commented 6 years ago

@ai Again, I agree, but their layouts need to be generated from layout.xml files used by the Swing client. Manually translating those into working HTML layouts would take like 50000 man days.

ai commented 6 years ago

For what? The postcss-cli doesn't issue a warning for this test case either.

You tested Vue with another CSS which must show warning.

You tested postcss-cli only with wrong CSS. This is why it didn't show you a warning.

franktopel commented 6 years ago

@ai Will post that over there with this test:

.warn {
    grid-column-end: 3;
    grid: subgrid;
    grid-template-areas: "head head"
                         "nav  main"
                         "foot ....";
}
ai commented 6 years ago

Yeap. And mention me there 😊. I will tell them what to fix.

franktopel commented 6 years ago

https://github.com/vuejs/vue-cli/issues/1601

franktopel commented 6 years ago

Maybe this would have been the more appropriate/specific place to raise the issue: https://github.com/postcss/postcss-loader

franktopel commented 6 years ago

Aside from that issue, what are you going to do about autoprefixer & grid-col-span / grid-row-span? Can it meaningfully be autoprefixed using a calculation and grid-column-end? If so, what needs to be put in one rule so the calculation can work?

ai commented 6 years ago

Aside from that issue, what are you going to do about autoprefixer & grid-col-span / grid-row-span

Try to find more recent article about Grid with final syntax. I think you need to use grid-row-start/grid-row-end (but without a laptop I can't say you exact code to fix your mixins).

franktopel commented 6 years ago

Go with the IE version and auto prefixer.

@Dan503 Please look at the Javascript snippet and the HTML example I posted above. Is there even a cross-browser solution possible if the .rowspan1 class never mentions where the cell starts?

Dan503 commented 6 years ago

Is there even a cross-browser solution possible if the .rowspan1 class never mentions where the cell starts?

If the statement doesn't mention either a start or an end point then no, Autoprefixer can't save you.

franktopel commented 6 years ago

So the approach would be to adjust the generator and render additional classes for the standard compliant browsers:

<div class="col4 row4 colspan5 rowspan20"></div>

would need additional CSS-classes

<div class="col4 row4 colspan5 rowspan20 colend9 rowend24"></div>

with

.colend9 {
  grid-column-end: span 9 /* colx + colspany */;
}

and

.rowend24 {
  grid-row-end: span 24 /* rowx + rowspany */;
}

These classes I assume the generator can calculate because he also knows in which (x/y) the container starts.

Or how would you advise approaching this? Would that approach also require defining grid-column-start and grid-row-start?

franktopel commented 6 years ago

These are the other classes generated by that grid-create.js:

.grid1 { display: -ms-grid; -ms-grid-columns: (1fr)[1]; -ms-grid-rows: auto; }
.col1 { -ms-grid-column: 1; }
.grid2 { display: -ms-grid; -ms-grid-columns: (1fr)[2]; -ms-grid-rows: auto; }
.col2 { -ms-grid-column: 2; }
.grid3 { display: -ms-grid; -ms-grid-columns: (1fr)[3]; -ms-grid-rows: auto; }
.col3 { -ms-grid-column: 3; }
.grid4 { display: -ms-grid; -ms-grid-columns: (1fr)[4]; -ms-grid-rows: auto; }
.col4 { -ms-grid-column: 4; }
.grid5 { display: -ms-grid; -ms-grid-columns: (1fr)[5]; -ms-grid-rows: auto; }
.col5 { -ms-grid-column: 5; }
.grid6 { display: -ms-grid; -ms-grid-columns: (1fr)[6]; -ms-grid-rows: auto; }
.col6 { -ms-grid-column: 6; }
.grid7 { display: -ms-grid; -ms-grid-columns: (1fr)[7]; -ms-grid-rows: auto; }
.col7 { -ms-grid-column: 7; }
.grid8 { display: -ms-grid; -ms-grid-columns: (1fr)[8]; -ms-grid-rows: auto; }
.col8 { -ms-grid-column: 8; }
.grid9 { display: -ms-grid; -ms-grid-columns: (1fr)[9]; -ms-grid-rows: auto; }
.col9 { -ms-grid-column: 9; }
.grid10 { display: -ms-grid; -ms-grid-columns: (1fr)[10]; -ms-grid-rows: auto; }
.col10 { -ms-grid-column: 10; }
.grid11 { display: -ms-grid; -ms-grid-columns: (1fr)[11]; -ms-grid-rows: auto; }
.col11 { -ms-grid-column: 11; }
.grid12 { display: -ms-grid; -ms-grid-columns: (1fr)[12]; -ms-grid-rows: auto; }
.col12 { -ms-grid-column: 12; }
.row1 { -ms-grid-row: 1; }
.row2 { -ms-grid-row: 2; }
.row3 { -ms-grid-row: 3; }
.row4 { -ms-grid-row: 4; }
.row5 { -ms-grid-row: 5; }
.row6 { -ms-grid-row: 6; }
.row7 { -ms-grid-row: 7; }
.row8 { -ms-grid-row: 8; }
.row9 { -ms-grid-row: 9; }
.row10 { -ms-grid-row: 10; }
/* ... 11 - 47 */
.row48 { -ms-grid-row: 48; }
.row49 { -ms-grid-row: 49; }
.row50 { -ms-grid-row: 50; }
Dan503 commented 6 years ago

That approach can work if you are able to generate the css as you work with the html rather than writing the css before hand.

In order to make that system work with Autoprefixer you would need to write styles like this.

.col4.colspan5 {
  grid-column: 4 / span 5;
}
row7.rowspan20  {
  grid-row: 7 / span 20;
}

It would be impossible to pre-write the css because there would be infinite possible combinations.

Dan503 commented 6 years ago

The colend9 and rowend24 classes are pointless.

franktopel commented 6 years ago

Why? That approach would solve the problem of having to create a huge number of css class combination rules.

It would work for

<div class="col4 row4 colspan5 rowspan20"></div>

which would generate to

<div class="col4 row4 colspan5 rowspan20 colend9 rowend24"></div>

but also for

<div class="col6 row2 colspan5 rowspan20"></div>

which would generate to

<div class="col6 row2 colspan5 rowspan20 colend11 rowend22"></div>

Dan503 commented 6 years ago

A cell can either span a number of columns or end at a certain line number.

If you say that a line starts at line 1, spans only 2 cells but some how ends at line 10... how exactly is that logically supposed to work?

Does it end at line 10 or only span 2 cells? It's impossible to do both at the same time.

franktopel commented 6 years ago

I don't get where you see that problem in the mentioned approach? A column that starts a column 4 and spans 5 columns will end at column 9, no?

Dan503 commented 6 years ago

Actually I think this would work except you would need to do all of the IE stuff manually. Autoprefixer won't help you.

:root {
  --col-span: 1;
  --row-span: 1;
}
.col4 {
  -ms-grid-column: 4;
  grid-column: 4 / span var(--col-span);
}
.row4 {
  -ms-grid-row: 4;
  grid-row: 4 / span var(--row-span);
}
.colspan5 {
 -ms-grid-column-span: 5;
 --col-span: 5;
}
.rowspan20 {
 -ms-grid-row-span: 20;
 --row-span: 20;
}

That approach uses CSS variables for the modern browsers and IE syntax for IE.

franktopel commented 6 years ago

@Dan503 My approach would be to let the generator tool calculate the appropriate end positions and use static CSS classes like .colend9 instead of using CSS variables - why would you not advise that?

franktopel commented 6 years ago

@ai This still needs your attention and some form of handling, even if that's only a warning that tells the user grid-column-span and grid-row-span have been removed from the specs. Until that is addressed, this should be re-opened.

ai commented 6 years ago

Oh, sure

Dan503 commented 6 years ago

I used the css variables because you can't declare grid-column: 4; in 1 class and grid-column: span 5; in another class and have them both work at the same time. One will overwrite the other.

By using a css variable it lets you avoid the overwrite issue.

What is your issue with using css variables? It's supported everywhere except IE and Opera Mini https://caniuse.com/#feat=css-variables

franktopel commented 6 years ago

@Dan503 Does that mean that what is now grid-column-start would be -ms-grid-column for IE11 and grid-column is the shorthand for grid-column-start / grid-column-end?