Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-conditional] testing support of properties and values with partial implementations #3559

Open
rachelandrew opened this issue Jan 26, 2019 · 15 comments

Comments

@rachelandrew
Copy link
Contributor

@rachelandrew rachelandrew commented Jan 26, 2019

There are a few places where @supports is unable to help authors as the property and value they want to test for is supported by the user agent, but not in the context they want to use it.

The obvious one (and where it keeps coming up at the moment) is testing support of any of the gap properties column-gap, row-gap or gap. I can test for support of column-gap and every browser will tell me it has support, however if I then try to use it in flexbox, I will only get a gap in Firefox, as that is the only user agent to have an implementation right now.

This means authors can't create a nice fallback with margins, then removing the margin on testing for support. It is likely that other box alignment properties - perhaps as browsers start to implement them for block layout, will have the same issue.

Other places this might be an issue are for fragmentation, I might want to test if fragmentation properties are available in a certain context.

It feels as if we need a way to ask for support of, for example, column: gap in display: flex. I don't know if that is even feasible in implementations, but it seems that this is likely to continue to be an issue as specs become more modular.

I found an older issue which also refers to partial implementations not being testable: #1167

@AmeliaBR
Copy link
Contributor

@AmeliaBR AmeliaBR commented Jan 26, 2019

This also comes up all the time when dealing with properties from SVG that are crossing over into CSS box layout & vice versa. For things like filter we have had browsers that support one syntax for SVG elements only, and a different syntax for everything except SVG elements, and both syntaxes would pass an @supports test.

(Aside: I really wish the spec for gap had strongly encouraged browsers not to support the generic property name until they implemented support for the generic feature. I was rather disappointed when browsers rushed to ship the easy parser implementation of the synonym before addressing their layout code, for this reason. But the broader issue still remains.)

@nigelmegitt
Copy link

@nigelmegitt nigelmegitt commented Jan 28, 2019

Perhaps the request should be that, in the absence of finer granularity queries, @supports should return false unless the implementation support exists in all usage contexts.

@rachelandrew
Copy link
Contributor Author

@rachelandrew rachelandrew commented Jan 28, 2019

"Perhaps the request should be that, in the absence of finer granularity queries, @supports should return false unless the implementation support exists in all usage contexts."

That might be a bit more useful, however then there is a property and value that the author knows is supported, but seems to be returning false. At that point we are asking them to understand all possible contexts in which that property vould be used.

The fragmentation properties are probably better to look at here than gaps, which are likely to be implemented - say if we did a specific masonry layout or something.

At the moment a property like break-before: avoid is specified for multicol, paged media, and regions. Assuming a wonderful world in which the property was supported in multicol and paged media, regions is a long way off, and probably won't happen in the current form. Which would mean that testing for break-* properties would be useless for the foreseeable future, as we don't have Regions so it can't be implemented in them. Most authors aren't even going to know about Regions and therefore why the property is returning false.

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Jan 29, 2019

There's no good solution to this that doesn't break the fundamental value proposition of @supports, which is that, since it's based purely on "does it parse", it requires no special table of return results in the browser, which history has shown us is destined to become some combination of stale and lies. I'm strongly against anything that tries to get "special-case" answers like this that aren't backed by a simple "try to parse it" mechanism.

(I definitely feel the pain, but it's not solveable here without making things overall worse.)

@BrentARitchie
Copy link

@BrentARitchie BrentARitchie commented Jan 30, 2019

Is it feasible to have @supports defined in the context of another selector? Something like:

body {
display: flex;
margin: 2rem;

  @supports(column:gap) {
  margin:0;
  column: gap;
  }
}

This way, the parsing stays simple and uses basic 'does it parse' logic.

@jonjohnjohnson
Copy link

@jonjohnjohnson jonjohnjohnson commented Jan 30, 2019

Related...

Though @supports(position:sticky) currently parses for all major vendors, Blink, which has the largest market share, still doesn't *fully support the value.

@SelenIT #2155 (comment)

It seems that for some reason Chrome reverted their changes for fixing position:sticky behavior on thead element.

@tabatkins I understand your sentiment about making things worse, but currently the often most efficient ways to deal with false @support scenarios are selector hacks, even if...

@dbaron #3051 (comment)

Using hacks that assume support for X is equivalent to support for Y is a bad idea if those hacks are targeting current browsers. Such hacks are safe only if the features are implemented in all current browsers and the equivalence holds in the old versions where they're not implemented.

And the resolution in #3051 seems to express an opposite stance, getting rid of the ability to use some of these selector hacks.

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Feb 2, 2019

Yup, selector hacks (or other browser-selection mechanisms) aren't great, but again, we already know that manually-maintained lists of support eventually rot, every single time it's ever been tried.

So it's a choice of somewhat encouraging bad individual-author behavior, or speccing bad UA behavior. I think the former does less damage overall.

@simlawr
Copy link

@simlawr simlawr commented Feb 15, 2019

Given, gap properties already exist for grid i.e. grid-gap, grid-column-gap, grid-row-gap, aliases for gap properties could also be added for Flexbox. This would enable detection for gap support specifically in Flexbox using the existing Feature Query syntax. For example:

@supports (flex-gap: 10px) {
  div {
    display: flex;
    gap: 10px;
  }
}

@supports not (flex-gap: 10px) {
  div {
    display: flex;
    margin: 10px;
  }
}

I'm not sure however, how appropriate this approach would be regarding other properties.

It certainly seams that as there is greater cross-pollination between specifications, this kind of situation is likely to become more prevalent and a sustainable solution would be nice.

@SebastianZ
Copy link
Contributor

@SebastianZ SebastianZ commented Nov 22, 2019

@simlawr That solution would somewhat cleanly solve the current issue regarding the -gap properties, as authors can easily understand it.
Though I believe it doesn't scale because it means that for every new property that is shared between different contexts, there needs to be an alias introduced only for the purpose of feature detection. That burdens authors, as they have to remember the aliases when doing feature detection, implementors, as they have to implement the aliases only applying in certain contexts, spec. authors because they will have to remember to add those aliases when the property is used in different contexts, and documentation writers because they will also have to cover those aliases.

Unfortunately, I don't have a better solution for this. There is probably no automated way of doing this kind of feature detection.

Sebastian

@Dan503
Copy link

@Dan503 Dan503 commented Apr 29, 2020

I really like Rachel's original suggestion although I would change it to "with" rather than "in" because you are more looking for a generic relationship between the 2 rather than a parent/child relationship.

@supports (gap: 1px) with (display: flex) {
   /* css code */
}

It doesn't sound that impossible for the computer to recognise.

The browser would need to check if both of the following conditions are true:

  • It understands both properties.
  • At least one of the properties has any sort of effect on the other.

If not then it returns false.

I am probably grossly simplifying the problem though. 😅

@foolip
Copy link
Member

@foolip foolip commented Oct 27, 2020

In the case of flex gap specifically, is there any workaround for web developers to detect support for it? It's only recently shipped in Chrome and even more recently landed in Safari Technology Preview, and without feature detection people will need to wait for another 3 years or so to be able to simply assume it will work.

@Dan503
Copy link

@Dan503 Dan503 commented Oct 27, 2020

In the case of flex gap specifically, is there any workaround for web developers to detect support for it?

Yes, there is but you have to use JS to detect it.

The following is based on this blog post:
https://ishadeed.com/article/flexbox-gap/

// Set up a cache to prevent a DOM element from getting created for every use of the function
let isSupported;

function checkFlexGapSupport() {
        // Use the cached value if it has been defined
	if (isSupported !== undefined) {
		return isSupported
	}

	// Create a flex container with row-gap set
	const flex = document.createElement('div')
	flex.style.display = 'flex'
	flex.style.flexDirection = 'column'
	flex.style.rowGap = '1px'
	flex.style.position = 'absolute'

	// Create two, elements inside it
	flex.appendChild(document.createElement('div'))
	flex.appendChild(document.createElement('div'))

	// Append to the DOM (needed to obtain scrollHeight)
	document.body.appendChild(flex)

        // Flex container should be 1px high due to the row-gap
	isSupported = flex.scrollHeight === 1

        // Remove element from the DOM after you are done with it
	flex.parentNode.removeChild(flex)

	return isSupported
}
@foolip
Copy link
Member

@foolip foolip commented Oct 27, 2020

Thanks @Dan503! I guess what people then typically to do is set a class on the body element and use that instead of @supports?

@tremby
Copy link

@tremby tremby commented Oct 28, 2020

That used to be very common, don't know if it still is these days. Often people would use a tool like Modernizr to do that.

@marcebdev
Copy link

@marcebdev marcebdev commented Dec 30, 2020

Is there any development on doing this either through an alias or an improvement to @supports? Using gap in the context of Flexbox is virtually non-existent to me since it's not checkable.

I've stumble upon the above modified Modernizr check. For simple cases it might actually be easier to use a mixin through some CSS framework to "mask" gap so for instance calling a mixing gap(value) to something like the over-simplified snippet below for demonstration purposes. After all, a fix for browsers still not supporting gap would be needed.

& > :not(:last-child) {
  margin-right: value;
}

BUT you do have to account for Flexbox direction and wrapping, so something more like flex-layout(value, direction, wrap) to make it more generic which can quickly make it a real pain vs using JS & DOM manipulation.

Resorting to either DOM manipulation or ignoring the feature I do hope there's some mediation without having to wait maybe another few years until gap is pretty safe. It seems following how @supports works generics, such as gap will simply need case-specific aliased names or they won't be able to be implemented correctly. It'd be quite unfortunate to see Modernizer forced to evolve into a bandaid of sorts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet