diff --git a/src/wp-includes/block-supports/typography.php b/src/wp-includes/block-supports/typography.php index 550eb7fb735fa..7e9b3d08892b5 100644 --- a/src/wp-includes/block-supports/typography.php +++ b/src/wp-includes/block-supports/typography.php @@ -454,6 +454,7 @@ function wp_get_computed_fluid_typography_value( $args = array() ) { * @since 6.1.0 * @since 6.1.1 Adjusted rules for min and max font sizes. * @since 6.2.0 Added 'settings.typography.fluid.minFontSize' support. + * @since 6.3.0 Introduced logarithmic scale factor to calculate a minimum font scale that tapers out as the font size increases. * * @param array $preset { * Required. fontSizes preset value as seen in theme.json. @@ -497,12 +498,14 @@ function wp_get_typography_font_size_value( $preset, $should_use_fluid_typograph : array(); // Defaults. - $default_maximum_viewport_width = '1600px'; - $default_minimum_viewport_width = '768px'; - $default_minimum_font_size_factor = 0.75; - $default_scale_factor = 1; - $has_min_font_size = isset( $fluid_settings['minFontSize'] ) && ! empty( wp_get_typography_value_and_unit( $fluid_settings['minFontSize'] ) ); - $default_minimum_font_size_limit = $has_min_font_size ? $fluid_settings['minFontSize'] : '14px'; + $default_maximum_viewport_width = '1600px'; + $default_minimum_viewport_width = '320px'; + $default_minimum_font_size_factor_max = 0.75; + $default_minimum_font_size_factor_min = 0.25; + $default_scale_factor = 1; + $has_min_font_size = isset( $fluid_settings['minFontSize'] ) && + ! empty( wp_get_typography_value_and_unit( $fluid_settings['minFontSize'] ) ); + $default_minimum_font_size_limit = $has_min_font_size ? $fluid_settings['minFontSize'] : '14px'; // Font sizes. $fluid_font_size_settings = isset( $preset['fluid'] ) ? $preset['fluid'] : null; @@ -557,10 +560,16 @@ function wp_get_typography_font_size_value( $preset, $should_use_fluid_typograph * the given font size multiplied by the min font size scale factor. */ if ( ! $minimum_font_size_raw ) { - $calculated_minimum_font_size = round( - $preferred_size['value'] * $default_minimum_font_size_factor, - 3 - ); + $preferred_font_size_in_px = 'px' === $preferred_size['unit'] ? $preferred_size['value'] : $preferred_size['value'] * 16; + + /* + * The scale factor is a multiplier that affects how quickly the curve will move towards the minimum, + * that is, how quickly the size factor reaches 0 given increasing font size values. + * For a - b * log2(), lower values of b will make the curve move towards the minimum faster. + * The scale factor is constrained between min and max values. + */ + $minimum_font_size_factor = min( max( 1 - 0.075 * log( $preferred_font_size_in_px, 2 ), $default_minimum_font_size_factor_min ), $default_minimum_font_size_factor_max ); + $calculated_minimum_font_size = round( $preferred_size['value'] * $minimum_font_size_factor, 3 ); // Only use calculated min font size if it's > $minimum_font_size_limit value. if ( ! empty( $minimum_font_size_limit ) && $calculated_minimum_font_size <= $minimum_font_size_limit['value'] ) { diff --git a/tests/phpunit/tests/block-supports/typography.php b/tests/phpunit/tests/block-supports/typography.php index 6cbd76788d9d9..3ad056b6c6380 100644 --- a/tests/phpunit/tests/block-supports/typography.php +++ b/tests/phpunit/tests/block-supports/typography.php @@ -293,6 +293,7 @@ public function test_should_generate_classname_for_font_family() { * * @ticket 56467 * @ticket 57065 + * @ticket 58523 * * @covers ::wp_get_typography_font_size_value * @@ -385,7 +386,7 @@ public function data_generate_font_size_preset_fixtures() { 'size' => '1.75rem', ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(1.313rem, 1.313rem + ((1vw - 0.48rem) * 0.84), 1.75rem)', + 'expected_output' => 'clamp(1.119rem, 1.119rem + ((1vw - 0.2rem) * 0.789), 1.75rem)', ), 'returns clamp value with em min and max units' => array( @@ -393,15 +394,15 @@ public function data_generate_font_size_preset_fixtures() { 'size' => '1.75em', ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(1.313em, 1.313rem + ((1vw - 0.48em) * 0.84), 1.75em)', + 'expected_output' => 'clamp(1.119em, 1.119rem + ((1vw - 0.2em) * 0.789), 1.75em)', ), 'returns clamp value for floats' => array( 'font_size' => array( - 'size' => '100.175px', + 'size' => '70.175px', ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(75.131px, 4.696rem + ((1vw - 7.68px) * 3.01), 100.175px)', + 'expected_output' => 'clamp(37.897px, 2.369rem + ((1vw - 3.2px) * 2.522), 70.175px)', ), 'coerces integer to `px` and returns clamp value' => array( @@ -409,15 +410,15 @@ public function data_generate_font_size_preset_fixtures() { 'size' => 33, ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(24.75px, 1.547rem + ((1vw - 7.68px) * 0.992), 33px)', + 'expected_output' => 'clamp(20.515px, 1.282rem + ((1vw - 3.2px) * 0.975), 33px)', ), 'coerces float to `px` and returns clamp value' => array( 'font_size_preset' => array( - 'size' => 100.23, + 'size' => 70.175, ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(75.173px, 4.698rem + ((1vw - 7.68px) * 3.012), 100.23px)', + 'expected_output' => 'clamp(37.897px, 2.369rem + ((1vw - 3.2px) * 2.522), 70.175px)', ), 'returns clamp value when `fluid` is empty array' => array( @@ -426,7 +427,7 @@ public function data_generate_font_size_preset_fixtures() { 'fluid' => array(), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 0.841), 28px)', + 'expected_output' => 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 0.789), 28px)', ), 'returns clamp value when `fluid` is `null`' => array( @@ -435,7 +436,31 @@ public function data_generate_font_size_preset_fixtures() { 'fluid' => null, ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 0.841), 28px)', + 'expected_output' => 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 0.789), 28px)', + ), + + 'returns clamp value where min and max fluid values defined' => array( + 'font_size' => array( + 'size' => '80px', + 'fluid' => array( + 'min' => '70px', + 'max' => '125px', + ), + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(70px, 4.375rem + ((1vw - 3.2px) * 4.297), 125px)', + ), + + 'returns clamp value where max is equal to size' => array( + 'font_size' => array( + 'size' => '7.8125rem', + 'fluid' => array( + 'min' => '4.375rem', + 'max' => '7.8125rem', + ), + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(4.375rem, 4.375rem + ((1vw - 0.2rem) * 4.298), 7.8125rem)', ), 'returns clamp value if min font size is greater than max' => array( @@ -447,7 +472,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(5rem, 5rem + ((1vw - 0.48rem) * -5.769), 32px)', + 'expected_output' => 'clamp(5rem, 5rem + ((1vw - 0.2rem) * -3.75), 32px)', ), 'returns value with invalid min/max fluid units' => array( @@ -487,18 +512,18 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', + 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 3.2px) * 60.938), 50rem)', ), 'returns clamp value where no fluid max size is set' => array( 'font_size_preset' => array( - 'size' => '28px', + 'size' => '50px', 'fluid' => array( 'min' => '2.6rem', ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 0.48rem) * -1.635), 28px)', + 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 0.2rem) * 0.656), 50px)', ), 'returns clamp value where no fluid min size is set' => array( @@ -509,7 +534,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 7.091), 80px)', + 'expected_output' => 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 4.851), 80px)', ), 'should not apply lower bound test when fluid values are set' => array( @@ -521,7 +546,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(0.5rem, 0.5rem + ((1vw - 0.48rem) * 8.654), 5rem)', + 'expected_output' => 'clamp(0.5rem, 0.5rem + ((1vw - 0.2rem) * 5.625), 5rem)', ), 'should not apply lower bound test when only fluid min is set' => array( @@ -532,7 +557,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(12px, 0.75rem + ((1vw - 7.68px) * 0.962), 20px)', + 'expected_output' => 'clamp(12px, 0.75rem + ((1vw - 3.2px) * 0.625), 20px)', ), 'should not apply lower bound test when only fluid max is set' => array( @@ -543,7 +568,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(0.875rem, 0.875rem + ((1vw - 0.48rem) * 36.779), 20rem)', + 'expected_output' => 'clamp(0.875rem, 0.875rem + ((1vw - 0.2rem) * 23.906), 20rem)', ), 'returns clamp value when min and max font sizes are equal' => array( @@ -555,7 +580,34 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(30px, 1.875rem + ((1vw - 7.68px) * 1), 30px)', + 'expected_output' => 'clamp(30px, 1.875rem + ((1vw - 3.2px) * 1), 30px)', + ), + + 'should apply scaled min font size for em values when custom min font size is not set' => array( + 'font_size' => array( + 'size' => '12rem', + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(5.174rem, 5.174rem + ((1vw - 0.2rem) * 8.533), 12rem)', + ), + + 'should apply scaled min font size for px values when custom min font size is not set' => array( + 'font_size' => array( + 'size' => '200px', + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(85.342px, 5.334rem + ((1vw - 3.2px) * 8.958), 200px)', + ), + + 'should not apply scaled min font size for minimum font size when custom min font size is set' => array( + 'font_size' => array( + 'size' => '200px', + 'fluid' => array( + 'min' => '100px', + ), + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(100px, 6.25rem + ((1vw - 3.2px) * 7.813), 200px)', ), ); } @@ -568,6 +620,7 @@ public function data_generate_font_size_preset_fixtures() { * @ticket 56467 * @ticket 57065 * @ticket 57529 + * @ticket 58523 * * @covers ::wp_register_typography_support * @@ -628,7 +681,7 @@ public function data_generate_block_supports_font_size_fixtures() { 'returns clamp value using default config' => array( 'font_size_value' => '15px', 'theme_slug' => 'block-theme-child-with-fluid-typography', - 'expected_output' => 'font-size:clamp(14px, 0.875rem + ((1vw - 7.68px) * 0.12), 15px);', + 'expected_output' => 'font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.078), 15px);', ), 'returns value when font size <= default min font size bound' => array( 'font_size_value' => '13px', @@ -638,7 +691,7 @@ public function data_generate_block_supports_font_size_fixtures() { 'returns clamp value using custom fluid config' => array( 'font_size_value' => '17px', 'theme_slug' => 'block-theme-child-with-fluid-typography-config', - 'expected_output' => 'font-size:clamp(16px, 1rem + ((1vw - 7.68px) * 0.12), 17px);', + 'expected_output' => 'font-size:clamp(16px, 1rem + ((1vw - 3.2px) * 0.078), 17px);', ), 'returns value when font size <= custom min font size bound' => array( 'font_size_value' => '15px', @@ -655,6 +708,7 @@ public function data_generate_block_supports_font_size_fixtures() { * * @ticket 56467 * @ticket 57065 + * @ticket 58523 * * @dataProvider data_generate_replace_inline_font_styles_with_fluid_values_fixtures * @@ -702,7 +756,7 @@ public function data_generate_replace_inline_font_styles_with_fluid_values_fixtu 'block_content' => '
A paragraph inside a group
', @@ -720,13 +774,13 @@ public function data_generate_replace_inline_font_styles_with_fluid_values_fixtu 'block_content' => 'A paragraph inside a group
', 'font_size_value' => '20px', 'should_use_fluid_typography' => true, - 'expected_output' => 'A paragraph inside a group
', + 'expected_output' => 'A paragraph inside a group
', ), 'return_content_with_first_match_replace_only' => array( 'block_content' => "A paragraph inside a group
A paragraph inside a group
A paragraph inside a group