-
Notifications
You must be signed in to change notification settings - Fork 110
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
Change minimum viewport width to be exclusive whereas the maximum width remains inclusive #1839
Conversation
…th remains inclusive This will allow for creating media queries that avoid any 1px gaps. The key code change is in `OD_URL_Metric_Group::is_viewport_width_in_range()` (and `isViewportNeeded` in `detect.js`). This also avoid the need to add the number 1 to the minimum viewport width which can be confusing given the known breakpoints. This instead moves the addition of 1 at the moment to `od_generate_media_query()` but this will be removed with resolution of #1696. Require that a viewport width and height for a URL Metric be at least 1px.
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
$last_link['maximum_viewport_width'] + 1 === $link['minimum_viewport_width'] | ||
$last_link['maximum_viewport_width'] === $link['minimum_viewport_width'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key change. The addition of 1 is no longer needed because the previous maximum is intended to equal the next minimum.
$groups = array(); | ||
$min_width = 0; | ||
foreach ( $this->breakpoints as $max_width ) { | ||
$groups[] = new OD_URL_Metric_Group( array(), $min_width, $max_width, $this->sample_size, $this->freshness_ttl, $this ); | ||
$min_width = $max_width + 1; | ||
$groups = array(); | ||
$min_width_exclusive = 0; | ||
foreach ( $this->breakpoints as $max_width_inclusive ) { | ||
$groups[] = new OD_URL_Metric_Group( array(), $min_width_exclusive, $max_width_inclusive, $this->sample_size, $this->freshness_ttl, $this ); | ||
$min_width_exclusive = $max_width_inclusive; | ||
} | ||
$groups[] = new OD_URL_Metric_Group( array(), $min_width, PHP_INT_MAX, $this->sample_size, $this->freshness_ttl, $this ); | ||
$groups[] = new OD_URL_Metric_Group( array(), $min_width_exclusive, PHP_INT_MAX, $this->sample_size, $this->freshness_ttl, $this ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key change. Note how there is no longer the need to add 1 to the maximum width to become the minimum width of the next group.
We could consider replacing PHP_INT_MAX
here with null
, to allow the maximum viewport width to be positive-int|null
. The logic would then need to check if OD_URL_Metric_Group::is_viewport_width_in_range()
the maximum_viewport_width
is null
, and if so it could always return true
if the provided viewport width is greater than the minimum_viewport_width
. This would match what I've implemented client-side in the isViewportNeeded()
function to avoid exporting PHP_INT_MAX
to the frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that od_generate_media_query()
supports this behavior, where you can either supply 0
or null
to omit as the minimum viewport width to omit the min-width
media query, whereas you can also supply null
or PHP_INT_MAX
as the maximum viewport width to omit the max-width
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of getting rid of the need for PHP_INT_MAX
here, to no longer have to export it, which in practice feels excessive anyway. I don't anticipate any viewports being wider than, let's say 10,000 px, and that's probably already excessive. I'm sure there are such cases, but in any case that's still miles away from PHP_INT_MAX
:)
So no longer using a concrete number here and instead truly indicating "unbounded" makes more sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented this in b4ea6bd
$viewport_width >= $this->minimum_viewport_width && | ||
$viewport_width > $this->minimum_viewport_width && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key change!
'minimum' => 0, | ||
'minimum' => 1, | ||
), | ||
'height' => array( | ||
'type' => 'integer', | ||
'required' => true, | ||
'minimum' => 0, | ||
'minimum' => 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important: Note how the minimum width/height for a URL Metric is now 1px (i.e. positive-int
)
* The comparison logic here corresponds with the PHP logic in `OD_URL_Metric_Group::is_viewport_width_in_range()`. | ||
* | ||
* @param {number} viewportWidth - Current viewport width. | ||
* @param {URLMetricGroupStatus[]} urlMetricGroupStatuses - Viewport group statuses. | ||
* @return {boolean} Whether URL Metrics are needed. | ||
*/ | ||
function isViewportNeeded( viewportWidth, urlMetricGroupStatuses ) { | ||
let lastWasLacking = false; | ||
for ( const { minimumViewportWidth, complete } of urlMetricGroupStatuses ) { | ||
if ( viewportWidth >= minimumViewportWidth ) { | ||
lastWasLacking = ! complete; | ||
} else { | ||
break; | ||
if ( viewportWidth === 0 ) { | ||
return false; | ||
} | ||
|
||
for ( const { | ||
minimumViewportWidth, | ||
maximumViewportWidth, | ||
complete, | ||
} of urlMetricGroupStatuses ) { | ||
if ( | ||
viewportWidth > minimumViewportWidth && | ||
( null === maximumViewportWidth || | ||
viewportWidth <= maximumViewportWidth ) | ||
) { | ||
return complete; | ||
} | ||
} | ||
return lastWasLacking; | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key change.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## trunk #1839 +/- ##
==========================================
- Coverage 65.89% 65.82% -0.07%
==========================================
Files 88 88
Lines 6878 6865 -13
==========================================
- Hits 4532 4519 -13
Misses 2346 2346
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
return null; | ||
} | ||
$media_attributes = array(); | ||
if ( null !== $minimum_viewport_width && $minimum_viewport_width > 0 ) { | ||
$media_attributes[] = sprintf( '(min-width: %dpx)', $minimum_viewport_width ); | ||
$media_attributes[] = sprintf( '(min-width: %dpx)', $minimum_viewport_width + 1 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The addition of 1 here can be redone as part of #1833. /cc @SohamPatel46
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the issue you mentioned potential issues with half pixels. By no means a blocker, but I would think that doing this here still leaves that problem unresolved for the largest viewport's minimum width.
Is there no way to use an exclusive minimum without providing a maximum with the new range syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but I figured to do that as part of #1833 since doing that change here would cause all of the snapshots to be invalidated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ef74635
to
0dafbb7
Compare
array_map( | ||
static function ( OD_URL_Metric $url_metric ): array { | ||
return $url_metric->jsonSerialize(); | ||
}, | ||
$group_collection->get_flattened_url_metrics() | ||
), | ||
JSON_UNESCAPED_SLASHES // No need for escaped slashes since not printed to frontend. | ||
$group_collection->get_flattened_url_metrics(), | ||
JSON_UNESCAPED_SLASHES // No need for escaping slashes since this JSON is not embedded in HTML. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bonus change referenced in #1156 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@westonruter This looks great, just a few minor comments. I think it would be great to implement getting rid of PHP_INT_MAX
, see https://github.com/WordPress/performance/pull/1839/files#r1939774669.
* @phpstan-param int<0, max> $minimum_viewport_width | ||
* @phpstan-param int<1, max> $maximum_viewport_width | ||
* @phpstan-param int<1, max> $sample_size | ||
* @phpstan-param int<0, max> $freshness_ttl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat, I didn't know you could do this :)
*/ | ||
function od_get_cache_purge_post_id(): ?int { | ||
$queried_object = get_queried_object(); | ||
if ( $queried_object instanceof WP_Post ) { | ||
if ( $queried_object instanceof WP_Post && $queried_object->ID > 0 ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just to satisfy PHPStan? Seems a bit odd of a check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is for the sake of PHPStan. It's so we can say that the function returns a positive-int
. Technically $queried_object->ID
can be zero or negative since at the the_post
action it can be overridden. In fact, the Customizer does this for nav menus which aren't yet saved in the DB: it provides negative values for the IDs to indicate nav menu items that haven't yet been inserted.
return null; | ||
} | ||
$media_attributes = array(); | ||
if ( null !== $minimum_viewport_width && $minimum_viewport_width > 0 ) { | ||
$media_attributes[] = sprintf( '(min-width: %dpx)', $minimum_viewport_width ); | ||
$media_attributes[] = sprintf( '(min-width: %dpx)', $minimum_viewport_width + 1 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the issue you mentioned potential issues with half pixels. By no means a blocker, but I would think that doing this here still leaves that problem unresolved for the largest viewport's minimum width.
Is there no way to use an exclusive minimum without providing a maximum with the new range syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@westonruter Thanks, LGTM!
( null === maximumViewportWidth || | ||
viewportWidth <= maximumViewportWidth ) | ||
) { | ||
return complete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
This is a dependency to fix #1696 and blocks #1833 from being merged. This change allows for creating media queries that avoid any 1px gaps. The key code change is in
OD_URL_Metric_Group::is_viewport_width_in_range()
(andisViewportNeeded
indetect.js
). This also avoid the need to add the number 1 to the minimum viewport width which can be confusing given the known breakpoints. This instead moves the addition of 1 at the moment tood_generate_media_query()
but this will be removed with resolution of #1696.As part of this, the viewport width and height for a URL Metric are now required to be at least 1px, whereas before they could theoretically be 0px (which doesn't make sense).
While auditing the types after the above change, I also improved the type specificity with PHPStan's richer types.
Note that all of the snapshot tests for Optimization Detective, Image Prioritizer, and Embed Optimizer are all passing without any modification in this PR. This shows that the code change does not impact the output.