Wednesday, 11 July 2018

Getting IE11 to play nicely with grid-area

I've been playing with CSS Grid layout lately within a Vue Component and I'm needing to place specific blocks within a grid, they are of an arbitrary position width and height and that all worked a treat within FireFox and Chrome... just not in, you guessed it, IE11.

So after banging my head against the issue for a few hours and trying everything I could think of I went to StackOverflow and asked. It seems I was being too helpful and adding the browser prefix rather than letting Vue do it for me. So far so good and StackOverflow provided the answer (thanks zero298), but it only went so far.

After looking at the issue some more I came up with the following script:

getStyle: function(x, y, a, b, c, d){
    var style = [];
    style.push("grid-row: " + x + ";");
    style.push("grid-row-span: " + d + ";");
    style.push("grid-column: " + y + ";");
    style.push("grid-column-span: " + c + ";");
    style.push("grid-area: " + x + " / " + y + " / " + a + " / " + b + ";");
    style.push("border: 1px solid white;");
    return style.join(" ");
}

I know that I'm using CSS for the border on the elements but IE11 doesn't support the grid-gap property for some reason, and rather than use browser detection, I figured it would be better to just do it this way for all elements. It's an interesting way of doing things as some of the properties are incompatible, which is why the decent bits of grid-area are left to the end and the IE11 specific bits get added first. IE11 doesn't support grid-area anyway so we're golden.

A little bit of extra work but should you examine the result in the bound style of an element you only see the appropriate CSS for the appropriate browser, which is nice. As I replied added in my original question on SO I just needed to trust Vue!

EDIT

I got to thinking about the variables I was passing to the function above and realised that the c and d variables could be derived from subtracting the width from the x coordinate and the depth of the block from the y coordinate. Not only does this meant that the number of variables I was passing was reduced (something of an issue as the functions I was calling this from were making the calculations on the fly) but it also makes it much clearer. This is the new function:

getStyle: function(x, y, width, depth){
    /***
     * X=Row , Y=Column
     * https://answers.yahoo.com/question/index?qid=20090609205915AASR51m&guccounter=1
     * IE11 has issues with grid-area as well as the syntax of grid-row and grid-column.
     * As such we need a polyfill for that that uses "-span" to indicate the "length" of the element
     * @param {number} x The "line" where the element should start on the horizontal grid (column) from the top
     * @param {number} y The "line" where the element should start on the vertical grid (row) from the left
     * @param {number} width The "line" where the element should end on the horizontal grid (column) from the top
     * @param {number} depth The "line" where the element should end on the vertical grid (row) from the left
     */
    var style = [];
    style.push("grid-row: " + x);
    style.push("grid-row-span: " + (width - x));
    style.push("grid-column: " + y);
    style.push("grid-column-span: " + (depth - y));
    style.push("grid-area: " + x + " / " + y + " / " + width + " / " + depth);
    return style.join("; ");
}