Problem/Motivation
#2260061: Responsive image module does not support sizes/picture polyfill 2.2 updated responsive image support to use the current spec for the picture element. The picture element can contain source elements, each with their own media query, which should be ordered from the largest possible breakpoint to the smallest. Thus that issue changed the weight of breakpoints in core breakpoints.yml files to reflect this change.
However the Toolbar module assumes that breakpoints are ordered from smallest breakpoint to largest breakpoint, as you would find in CSS.
As noted in #2423577: Remove Seven's appearance-page.css, the change in breakpoint order caused regressions in toolbar behavior. For example, the button to switch from the vertical to the horizontal toolbar doesn't appear at desktop sizes, as demonstrated here:
https://www.drupal.org/files/issues/Welcome_to_Site-Install___Site-Insta...
https://www.drupal.org/files/issues/Welcome_to_Site-Install___Site-Insta...
Proposed resolution
The simplest fix for this would seem to be changing the order of the breakpoints in the Toolbar module so that they are once again weighted from smallest to largest.
If someone were to use the Toolbar breakpoints to create a responsive image style, the order of the breakpoints would be incorrect. But it wouldn't make much sense to make a responsive image style off of those breakpoints, so hopefully that would be okay.
Right now Toolbar and Responsive Image are the only modules that make use of breakpoints. If some sort of layout module tried to use breakpoints that would also be logical to use with responsive images, it would need to account for this ordering discrepancy.
Beta phase evaluation
Issue category | Bug because the toolbar is not functioning correctly due to the underlying problem solved by this issue. The button to switch between vertical/horizontal toolbar layouts is not appearing at desktop sizes. |
---|---|
Issue priority | Major because the toolbar still functions, but has a bug that makes it significantly less useful. |
Prioritized changes | The main goal of this issue is fixing a bug introduced by a recent critical issue: #2260061: Responsive image module does not support sizes/picture polyfill 2.2 |
Disruption | Disruption in this issue is primarily limited to the Toolbar and Responsive Image modules, and those disruptions are handled within this patch. No known contributed modules make use of breakpoints.yml at this time, and it is very unlikely there are nearly any sites with a breakpoints.yml in their theme used for responsive images. |
Comment | File | Size | Author |
---|---|---|---|
#73 | Welcome_to_drupal_8_0_x___drupal_8_0_x.png | 11.18 KB | joelpittet |
#72 | interdiff-2424805-71-72.txt | 3.33 KB | RainbowArray |
#72 | 2424805-72-breakpoint-weights.patch | 12.67 KB | RainbowArray |
#44 | 2424805-diff-37-44.txt | 2.57 KB | vijaycs85 |
#44 | 2424805-44.patch | 13.39 KB | vijaycs85 |
Comments
Comment #1
RainbowArrayHere's a patch that orders the toolbar breakpoints from smallest to largest.
Comment #2
RainbowArrayComment #3
joelpittetThank you for resolving the issue @mdrummond.
Comment #4
Jelle_SIMHO, ordering them in code would be better. You're right in saying it wouldn't make much sense to make a responsive image style off of those breakpoints, but i'd do it just for consistency.
Comment #5
joelpittet@Jelle_S feel free to provide a better patch if you are so inclined, I'm just trying to resolve the regression. And this patch was MVC to do that.
Comment #6
RainbowArrayI have a patch that does what Jelle suggested. Uploading in a sec.
Comment #7
RainbowArrayFound where breakpoints are used in toolbar module: this is the only place they are used. I agree it is better to make the change here, as this allows us to keep the order of breakpoints consistent within breakpoints.yml files.
Other modules that used breakpoints could use a similar pattern to switch the order of breakpoints if necessary.
Comment #8
joelpittetI prefer the first one, it was explicit in the order defined by the weights in the yml. This obscures the expected order as it was defined and could even lead to confusion of how the weights work.
Comment #10
RainbowArrayI disagree. If we change the weight order in the breakpoints.yml file then you have to know how a breakpoints.yml file will be used in order to determine the order. Right now that's not much of an issue. However, in theory if there was a future layout module that made use of breakpoints.yml, what then? In theory those breakpoints would be useful for both layout and responsive images. If this theoretical layout module ordered breakpoints from smallest viewport to largest (as is typical in CSS), the module would need to be responsible for re-ordering the breakpoints. If not, then the breakpoints couldn't be used in the responsive image module.
I'd much rather have explicit rules for how how a breakpoints.yml should order its breakpoints. That provides a lot more flexibility in how those breakpoints can be used.
Comment #11
joelpittet@mdrummond: if you just array_reverse() someone changes the yml weights and boom broken again.
If you want to force a direction, sort the array.
Still those weights are disingenuous if you start hardcoding the order overrides further down the line.
Comment #12
RainbowArrayThe weights could be taken as explicitly declaring the order of the breakpoints based on viewport size (something that couldn't be detected just by evaluating the media query).
Those weights are used in breakpointManager()->getBreakpointsByGroup in this line:
So if we're going to use a reverse_array that may be the place to do it. Provide a variable for getBreakpointsByGroup, something like $reverse_sort, that allows the order to be switched.
That way we can set up consistent pattern for how breakpoints.yml should be ordered, and if a module (like toolbar), needs a different order, it can request one.
Comment #13
Jelle_SI like #12.
I think it's safe to assume that a module or theme maintainer knows what (s)he is doing when changing weights of breakpoints. If they don't, they'll probably look for examples in Drupal core. If we then use different logic in different places for assigning weights, that will lead to confusion. So for me adding the
$reverse_sort
parameter togetBreakpointsByGroup
sounds good!Comment #14
Jeff Burnz CreditAttribution: Jeff Burnz commentedI have that theoretical layout system already in operation which uses Breakpoints. The recent patch to responsive images/breakpints reversed breakpoints and broke layouts that use cascading media queries, however I rolled with that because that was such a huge patch and I did not want to delay it anymore, but this is less than ideal I think because it breaks the mental model of how breakpoints typically work (small to large).
Personally I would have preferred it to be Responsive Images that ask for a reversed array and everyone else gets something that far better matches themers typical mental model, one based around how cascading media queries are typically used most of the time.
Thats just my 2 cents anyway, I can reverse the array and was going to do it today when I saw this issue pop up, if you end up leaving Breakpoints how it is and provide a reversed array for toolbar and my project, great, I'd be happy with that also, I'm not hard out arguing for major change, but just mindful of we are breaking the mental model here.
Comment #15
joelpittetGood point Jeff Burnz. I'd prefer if the breakpoints are set back to the way they were and reverse them for responsive images as the exception.
It sounds like from mdrummond and Jeff burns that would be fitting the mental model? Please correct me if I've misinterpreted.
Comment #16
Jelle_S#15: That's the way I understood it as well. Sounds good to me :-)
Comment #17
RainbowArrayThat would mean finding where the responsive image module gets breakpoints, and requesting the reverse order, but yes, I think that's possible. I do like emphasizing that typically you should order breakpoints from smallest to largestt.
Comment #18
Jelle_S@mdrummond That would be in these two places:
ResponsiveImageStyleForm.php line 103
responsive_image.module line 188
Comment #19
RainbowArrayThis adds a new option to getBreakpointsByGroup, $size_order, which defaults to 'small-to-large'. If this option is set to 'large-to-small', then the breakpoint array is reversed. The responsive image module now passes in this large-to-small option.
This should also change all breakpoints.yml files in core so that the weight starts at 0 for the smallest viewport size and increases with the viewport size. Wouldn't be a bad idea for people to check if I missed anything.
There may well be some better ways to write this code, so I welcome feedback. I did test, and this correctly orders breakpoints for both responsive images and the toolbar.
Comment #20
attiks CreditAttribution: attiks commentedI guess we can do this in one line.
not really sure about the possible values, it doesn't feel like Drupal, but it works for me.
I think we mostly try to use a boolean, maybe something like $reversed_order = FALSE
Comment #21
joelpittetI agree with @attiks likely should be a boolean.
array_reverse() doesn't enforce that it will always be small to large or large to small, it just enforces the opposite of what was defined in the breakpoints.
It's sorted be weight, so there is a lot of assumptions going on here...
Comment #22
attiks CreditAttribution: attiks commented#21 We need to use the weight, there's no easy way to sort breakpoints from "small" to "large", we had a look at it last year, but there's no manageable solution. That's why the weight was added, so a themer can order them.
Sort is done by:
uasort($breakpoints, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
, right before the array_reverse.Comment #23
RainbowArrayI changed the variable to $reverse_order, a boolean, as suggested, and moved the reversal into only one line. I also found some more breakpoints test files to fix, as well as the accompanying tests. Hopefully this will stay green with these changes.
I agree with attiks: there is no perfect way to ensure size order. We were already relying on weights to do that. This just provides the option to reverse the order of those weights as necessary.
Comment #24
attiks CreditAttribution: attiks commentedNot really sure, but do we need a (unit) test, to test the reverse_order
Comment #25
RainbowArrayYes, I was thinking we should probably test that. Writing tests isn't my strength, so if somebody else wants to give that a go, that would be great. Otherwise I'll try to figure it out.
Comment #26
RainbowArrayOkay, adding in a test on the reverse order.
Comment #28
RainbowArrayFixing a bug (hopefully).
Comment #29
RainbowArrayComment #30
Jelle_SCouple of nitpicks:
s/true/TRUE/
And I think we generally use reverse (vs reverses) in core, but I'm not sure about that.
s/size_order/reverse_order/
Comment #31
YesCT CreditAttribution: YesCT commented#2431465: the orientation toggle toolbar button is missing initially, until resize I think is a duplicate.
Comment #32
YesCT CreditAttribution: YesCT commentedchanges from #30 and...
1.
https://www.drupal.org/node/1354#types
boolean -> bool
https://www.drupal.org/node/1354#types
2.
https://www.drupal.org/node/1354#order
"Separate different-type sections by a blank line (for instance, all the @param documentation goes together, with a blank line before the first parameter and a blank line after the last parameter before the @return section starts). "
Comment #33
attiks CreditAttribution: attiks commentedAssuming bot is happy, this should be fine.
I think committing this should be allowable, since the other patch broke the toolbar navigation, we probably need a follow up issue to add tests for the toolbar module.
Comment #35
RainbowArrayWe probably should have a change record to explain how people should order breakpoints in a breakpoints.yml file.
Comment #36
xjmProbably-duplicate: #2438715: Toolbar can no longer swap between horizontal and vertical mode on initial page load
Comment #37
xjmAttempted reroll. One merge conflict:
Comment #38
xjmConfirmed #2438715: Toolbar can no longer swap between horizontal and vertical mode on initial page load is resolved by #37.
Is there any way we could test part of this? Not the doodad itself, obviously.
If there is a CR, should it be on the issue that introduced the regression as well?
Comment #39
xjmRelated regression: #2439483: Toolbar styling is broken on minimal
Comment #41
saltednutReroll from RTBC'd patch applies cleanly and said "doodad" is showing up after a clean install via manual test but yeah, not sure how this gets tested otherwise.
The new patch name including "bartik" is a bit of a red herring. Seems like we're touching seven, breakpoints and other stuff. Might be confusing for the core committers but thats such a strange nitpick that I'm still going to re-RTBC this based on #33.
Comment #42
alexpottThis is has to be outside of the static and and permanent caching. The test does not test the order at all. In fact the call to getBreakpointsByGroup() here returns exactly the same order as the first call to the method in this test.
Comment #43
vijaycs85Working on this...
Comment #44
vijaycs85Addressed both points in #42
Comment #46
vijaycs85random fail...
Comment #48
RainbowArraySet up a basic change record, feel free to modify: https://www.drupal.org/node/2472065
Comment #49
RainbowArrayComment #50
ifrikreviewing it now
Comment #51
ifrikPatch #44 works for me.
The button to move the tool bar from horizontal to vertical position is present again at larger window size, works correctly, and is not displayed on smaller window size.
Comment #52
ifrikReviewing it properly now
Comment #53
RainbowArrayUpdated the change notice to make it more clear, as per recommendations from @YesCT: https://www.drupal.org/node/2472065
Comment #54
attiks CreditAttribution: attiks commentedPatch is looking good and CR is good
Comment #55
xjmReviewing this.
Comment #56
xjmThanks for the manual testing and the change record.
Always doing this after the breakpoints are loaded from cache makes sense. Thanks @vijaycs85.
Is it also possible to add test coverage for the cache invalidation? Are there steps I could use in manual testing to confirm that there isn't a caching issue?
At first I was hesitant about adding this new complexity to the API, but after reading the issue, it seems reasonable. However, it's not clear from this documentation why I would want to reverse the order of the breakpoints. Can we clarify that?
I also reviewed the change record. Overall it's nicely detailed. The two different sections are a little confusing because it first makes a declaration about how breakpoints should be ordered, but then goes on to talk about the parameter to reverse them or not. Similarly to in my second point above, could we simplify the change record a little bit to focus on the fact that there is (if I understand it right), maybe a majority usecase and minority usecase for the ordering, and what examples are? It doesn't need to specifically say that "responsive image needed this but toolbar did that so we made this change", but we can still use those two modules as examples of when we'd use one ordering or the other.
I'm glad to see this patch nearly ready; this bug is annoying for sure.
Comment #57
RainbowArrayI can work on the change record some more. Right now as far as I know the only use cases for breakpoints.yml are the Toolbar and Responsive Image modules. In theory there could be some layout modules that make use of breakpoints.yml in the future, but I don't believe those exist yet.
The bottom line is that within CSS, when you're using media queries for layout, generally those are structured with min-width, starting from small viewport sizes and increasing to large sizes. That allows you to have mobile styles first, and only add in media queries for larger sizes. This makes the CSS more robust, as even in theory if there's something that doesn't understand media queries, the mobile styles still show up.
However, with responsive images, the reverse is true: the picture element (or sizes attribute) will select the first media query it encounters which matches the viewport size, whether on a source element or in a sizes attribute. So if you're using min-width for that, the largest viewport size needs to come first in the list.
So... viewports small to large for anything with layout CSS (Toolbar module) and viewports large to small for anything using responsive images (Responsive Images module). There are more likely to be modules added that deal with layout CSS, so small to large makes the most sense as the default.
I can try to rework the above into the change notice.
Getting an explanation like that into the API documentation seems more challenging, but maybe there's a brief way to do it.
I don't know how to test the cache invalidation. Any takers on that part of the fixes?
Thanks for the review @xjm!
Comment #58
RainbowArrayUpdated the change notice to better explain why we are doing this. Feedback welcome: https://www.drupal.org/node/2472065
Comment #59
RainbowArrayAdded beta evaluation.
Comment #60
YesCT CreditAttribution: YesCT commentedWe still need to answer these questions from #56
1) "Is it also possible to add test coverage for the cache invalidation?"
[edit:]
maybe see \Drupal\toolbar\Tests\ToolbarAdminMenuTest::testMenuLinkUpdateSubtreesHashCacheClear for an example
2) "Are there steps I could use in manual testing to confirm that there isn't a caching issue?"
3) and we need to update the documentation to address
"However, it's not clear from this documentation why I would want to reverse the order of the breakpoints. Can we clarify that?"
Comment #61
lauriiiTo find out how to write a reroll, check out this page: https://www.drupal.org/patch/reroll
Comment #62
marcoscanoThanks for the reroll instructions @laurii.
Attached a first attempt to reroll it
Comment #63
marcoscanoSorry forgot to switch issue status
Comment #64
lauriiiThanks for the reroll! Removing the tag because no reroll needed anymore :) We still need tests for this patch. Here's a great instructions for that: https://www.drupal.org/contributor-tasks/write-tests
Comment #65
ifrikI've tested the UI on a minimal install.
After enabling toolbar and breakpoint module, the button to toggle between horizontal and vertical display is initially not displayed.
When I reduce the size of the browser window, the toolbar automatically is moved vertically, but no button is displayed.
After increasing the window size again the button is displayed and can be used to toggle.
When I move to a different page in the site, the button is once again not displayed.
Comment #66
lauriiiI guess there is a test coverage already
Comment #67
lauriiiComment #68
idflood CreditAttribution: idflood at Stimul.ch commentedI've tested the patch in #62 and it still applies fine and resolve the issue.
I might be wrong but I think that if a module or theme only needs breakpoints to interact with css media queries it would make sense to reverse the order of breakpoints. This ways breakpoints are consistent with how we generally define media queries in css (smaller to larger).
If a module or theme needs breakpoints to interact only with responsive images then it should not use the reverse option.
If it use breakpoints for css media queries and images then it should play with the reverse option to have the good order depending on the need.
Comment #69
joelpittetThanks @idflood let's get this in:)
Defining them from mobile first perspective is great +1. And if they are gotten in reverse when they need to be reversed that also makes sense.
My only gripe is we do far too many array_reverse calls in the theme system than should be necessary but that is unrelated to this case:P
Comment #70
joelpittetDiscussing with @mdrummond and @webchick on IRC. The new param needs better doxygen comments to explain when to use it. But I'd be inclined to just remove it and if someone needs the reverse they can reverse the output after they call it (responsive image I'm looking at you)
The changes to the weights in this patch look wonderful still though, I'd not change those.
Comment #71
RainbowArrayChanging the patch so the array is reversed in responsive image module rather than in breakpoint module.
Comment #72
RainbowArrayCleaned up breakpoint manager and improved code comments.
Comment #73
joelpittetThank you for updating the comments to make them clearer, I think that helps a bunch.
And this approach seems a bit nicer than adding a new param. Back to RTBC.
Comment #74
webchickAwesome, this is much more along the lines of what I expected. Thanks too for the greatly expanded comments in responsive_image module explaining why these backflips are necessary.
The only other nit I see is:
At this point, that test is literally just ensuring array_reverse() works, which is not our job. :) So removed that chunk and...
Committed and pushed to 8.0.x. Thanks! So great to have this one put away!