From c4a50f7c7a15635fc33579599c0a414597eb71bc Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 18 Nov 2025 13:38:40 +0100 Subject: [PATCH 01/21] merge conflict --- files/en-us/web/css/guides/values_and_units/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/css/guides/values_and_units/index.md b/files/en-us/web/css/guides/values_and_units/index.md index 393959375a980cf..48ed170e637a201 100644 --- a/files/en-us/web/css/guides/values_and_units/index.md +++ b/files/en-us/web/css/guides/values_and_units/index.md @@ -216,7 +216,7 @@ The CSS values and units module also introduces the [``](/en-US/docs/ - : A look at some of the most frequently used value types, what they are, and how they work. - [CSS value serialization](/en-US/docs/Web/API/CSS_Object_Model/CSS_value_serialization) - - : How [CSSOM APIs](/en-US/docs/Web/API/CSS_Object_Model) serialize color and other values into standardized string representations. + - : How [CSSOM APIs](/en-US/docs/Web/API/CSS_Object_Model) serialize values into standardized string representations. ## Related From feffb7dcaae73721256ea93b3d8c6a66d135d9ac Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 18 Nov 2025 15:14:11 +0100 Subject: [PATCH 02/21] revert local issue --- files/en-us/web/css/guides/values_and_units/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/css/guides/values_and_units/index.md b/files/en-us/web/css/guides/values_and_units/index.md index 48ed170e637a201..393959375a980cf 100644 --- a/files/en-us/web/css/guides/values_and_units/index.md +++ b/files/en-us/web/css/guides/values_and_units/index.md @@ -216,7 +216,7 @@ The CSS values and units module also introduces the [``](/en-US/docs/ - : A look at some of the most frequently used value types, what they are, and how they work. - [CSS value serialization](/en-US/docs/Web/API/CSS_Object_Model/CSS_value_serialization) - - : How [CSSOM APIs](/en-US/docs/Web/API/CSS_Object_Model) serialize values into standardized string representations. + - : How [CSSOM APIs](/en-US/docs/Web/API/CSS_Object_Model) serialize color and other values into standardized string representations. ## Related From 9d9ee4628a5797e60f9c84fb65567bc85e423c6d Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 25 Nov 2025 12:10:19 +0100 Subject: [PATCH 03/21] CSS scroll driven animation guide: range insets --- .../guides/scroll-driven_animations/index.md | 2 + .../timeline_insets/index.md | 306 ++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 files/en-us/web/css/guides/scroll-driven_animations/timeline_insets/index.md diff --git a/files/en-us/web/css/guides/scroll-driven_animations/index.md b/files/en-us/web/css/guides/scroll-driven_animations/index.md index e2f90539d47380a..bae467cce377015 100644 --- a/files/en-us/web/css/guides/scroll-driven_animations/index.md +++ b/files/en-us/web/css/guides/scroll-driven_animations/index.md @@ -145,6 +145,8 @@ Scroll the element in the inline direction to see its background color change. S - [Scroll-driven animation timelines](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines) - : Scroll-driven animation timelines and creating scroll-driven animations. +- [Effective scroll-driven animations](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timesline_insets) + - : Changing the range of scroll driven animations with insets, ranges, and keyframe selectors. ## Related concepts diff --git a/files/en-us/web/css/guides/scroll-driven_animations/timeline_insets/index.md b/files/en-us/web/css/guides/scroll-driven_animations/timeline_insets/index.md new file mode 100644 index 000000000000000..ce60fe2c2fc16ae --- /dev/null +++ b/files/en-us/web/css/guides/scroll-driven_animations/timeline_insets/index.md @@ -0,0 +1,306 @@ +--- +title: Effective scroll-driven animations +slug: Web/CSS/Guides/Scroll-driven_animations/Timeline_insets +page-type: guide +sidebar: cssref +--- + +Scroll driven animations are elements that animate as the user scrolls. By default, scroll-driven animations start and end at the edges of the scrollport or viewport, depending on the animation type. However, this isn't always what you want. Often, effective animations either occur when the element being animated is in the center of it's container or is done animating by the time it reaches that point. In this guide, we look at controlling the start and ends of scroll-driven animation by via @keyframe definitions, animation range properties, and setting insets. + +## Scroll-driven animation primer + +[CSS keyframe animations](/en-US/docs/Web/CSS/Guides/Animations/Using#defining_an_animation_sequence_using_keyframes) can be linked to scrolling thanks to features defined in the [CSS scroll-driven animations](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations) module. This module defines methods enabling progressing {{cssxref("@keyframes")}} animations along a scroll-progress or view based timeline instead of the default time-based document timeline. + +In CSS, animations are created by attaching keyframe animations to an element using the {{cssxref("animation-name")}} property (or {{cssxref("animation")}} shorthand). The animation moves from the `from` or `0%` keyframe to the `to` or `100%` keyframe based on the {{cssxref("animation-timeline")}}. By default, this is the [DocumentTimeline](/en-US/docs/Web/API/DocumentTimeline), with each {{cssxref("animation-iteration")}} taking as long as the time defined by the {{cssxref("animation-duration")}} property. + +View progress timeline are often used to create scroll reveals, such as fading in images or text sections, animated carousel gallery pages, highlighting nodes in a vertical or horizontal timeline layout as they reach a specific point in the viewport. See the [scroll driven animation timeline](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines) guide to learn how to create scroll-driven animations that run on a scroll-progress or view-progress timeline, which is driven by the scrolling of an element's contents, rather than the passing of time. + +Do use CSS, instead of JavaScript, to create view progress animations as tying an element's entry and exit from the scroll container's viewport, or {{glossary("scroll port")}} using the {{cssxref("view()")}} function as the value of the `animation-timeline` property is more performant than using JavaScript's {{domxref("Intersection Observer API")}}. + +## Scroll progress timelines + +With _scroll progress timeline_, the timeline progresses based on the scrolling of the scroller either horizontally or vertically. + +In this example, we have directions to and from two monuments, with a fake map between them that we want to animated in from fully transparent and scaled down to fully opaque and full size as we scroll down the page. + +To create an animation effect, we need an animation. We define a keyframe animation that makes the element on which it is applied go from fully transparent and scaled down, to fully opaque and at it's default size: + +```css live-sample___default live-sample___range +@keyframes someChangeEffect { + 0% { + opacity: 0; + scale: 0; + } + 100% { + opacity: 1; + scale: 1; + } +} +``` + +We apply the animation and a scroll timeline to the element we want to animate: + +```css live-sample___default live-sample___selector +.animatedElement { + animation: someChangeEffect 1ms linear; + animation-timeline: scroll(); +} +``` + +```html hidden live-sample___default live-sample___selector live-sample___range +
+
+

Directions

+

Lincoln Memorial to Martin Luther King, Jr. Memorial

+
    +
  1. Head south on Lincoln Memorial Circle
  2. +
  3. Turn right toward Independence Ave
  4. +
  5. Turn left onto Independence Ave
  6. +
  7. Turn right onto West Basin Dr
  8. +
  9. Look up when you reach 64 Independence Ave!
  10. +
+
+

Martin Luther King, Jr. Memorial to Lincoln Memorial

+
    +
  1. Head north toward Independence Ave SW
  2. +
  3. Turn left onto Independence Ave
  4. +
  5. Turn right toward the Korean War Veterans Memorial
  6. +
  7. Take a photo of the memorial as you walk past it.
  8. +
  9. Head north on Lincoln Memorial Circle
  10. +
  11. Look up. You can't miss it!
  12. +
+
+
+``` + +```css hidden live-sample___default live-sample___selector live-sample___range +main { + width: 400px; + padding: 1em; + height: 300px; + overflow: scroll; + border: 1px solid; + background-color: beige; + font-family: sans-serif; +} + +li { + margin-bottom: 0.75lh; +} + +.animatedElement { + height: 200px; + width: calc(300px - 2em); + margin: auto; + background-color: forestgreen; + background-image: + repeating-linear-gradient(37deg, transparent 0 52px, beige 52px 57px), + repeating-linear-gradient(94deg, transparent 0 52px, beige 52px 57px); + border: 1px solid; +} +``` + +{{EmbedLiveSample("default", "100%", "350")}} + +Scroll down from the first set of directions to the second set, and you'll notice the animated element appearing as you scroll. You may note the main problem with the animation: the element is only fully opaque at full size when it exits the screen. Let's fix this! + +## Controlling insets with @keyframe selectors + +Because the `100%` is generally reached when the element leaves the viewport, you likely want to set the final effect of your animation in a keyframe block that occurs well before the end of the animation. You can set your completed effect within the `20%`, `50%`, or `80%` keyframe block rather than using the `to` or `100%` keyframe to ensure the element finishes animating while still in view. + +To make the map element full size and fully visible earlier, and then have it reverse the animation as we scroll past the element and have it begin fading out as it reaches the top of the scroll port, we change the keyframe selector values. Here we set the element to be fully visible 20% and stay visible through 80%, before fading out by changing the selector for the hidden state to `0%, 100%` and the selector for the visible state to `20%, 80%`, : + +```css live-sample___selector +@keyframes someChangeEffect { + 0%, + 100% { + opacity: 0; + scale: 0; + } + 20%, + 80% { + opacity: 1; + scale: 1; + } +} +``` + +{{EmbedLiveSample("selector", "100%", "350")}} + +When the element comes into view as you scroll down the page, the map-like element animates in, reaching it's full size 20% of the way through the scroll port and starts fading out when it reaches 80%. Unfortunately, this creates a really fast fade out. In addition, this method requires redefining your keyframe animations, and may necessitate multiple similar animation definitions that create the same effect but at different points in the scrolling. Fortunately, there are other solutions. + +## Controlling insets with animation-range + +By default, the position in the scroll range is converted into a percentage of progress — `0%` at the start and `100%` at the end. This animation range can be controlled via the {{cssxref("animation-range")}} properties. The `animation-range` property is shorthand for {{cssxref("animation-range-start")}} and {{cssxref("animation-range-end")}}, in that order. It is used to set the start and end of an animation's attachment range along its timeline, i.e., where along the timeline an animation will start and end. + +```css live-sample___range +.animatedElement { + animation: someChangeEffect 1ms linear; + animation-timeline: scroll(); + + animation-range: 20% 80%; +} +``` + +{{EmbedLiveSample("range", "100%", "350")}} + +## View progress timelines + +You can also progress an animation based on the change in visibility of an element inside a scroller — this is done via _view progress timelines_. Instead of tracking the scroll offset of a scroll container, view progress timelines track the relative position of an element, called the _subject_, within a scrollport. The progression of an animation's keyframes is based on the _visibility_ of the subject inside the scroller. Unlike scroll progress timelines, with view progress timelines, you can't specify the scroller — the subject's visibility is always tracked within its nearest ancestor scroller. + +A view progress timeline animation only occurs when the element is visible within its scrollport. Timeline progress starts at `0%` when the tracked subject starts intersecting the scrollport at the block or inline end edge. The `100%` occurs when the subject exits the scrollport at the block or inline start edge. + +Because the `100%` is generally reached when the element leaves the viewport, you likely want to set the final effect of your animation in a keyframe block that occurs well before the end of the animation. You can set your completed effect within the `20%`, `50%`, or `80%` keyframe block rather than using the `to` or `100%` keyframe to ensure the element finishes animating while still in view. + +With view progress timelines, you can adjust the view progress visibility range. +Use {{cssxref("view-timeline-inset")}}, part of the {{cssxref("view-timeline")}} shorthand, to adjust when the subject is considered to be in view. The default value is `auto`. The effect of any non-`auto` inset value is as if you moved the edges of the scroll port: a positive inset value creates an inward adjustment, and a negative value creates an outward adjustment. + +Similar to scroll progress timelines, the view progress timeline can be named or anonymous. + +### Named view progress timeline + +A _named view progress timeline_ is one where the subject is explicitly named using the {{cssxref("view-timeline-name")}} property, a component of the `view-timeline` shorthand. The `` name is then linked to the element to animate by specifying it as the value of that element's `animation-timeline` property. + +With named view progress timelines, the element to animate does not have to be the same as the subject. In other words, the element controlling the timeline doesn't have to be the same as the element being animated. This means you can animate one element based on another element's movement within its scrollable container. + +Here we use the {{cssxref("view-timeline-name")}} property to name an element, identifying the element itself as the source of a view progress timeline. We then set that name as the value of the `animation-timeline` property. + +```css live-sample___named_view +.item { + animation: action 1ms linear; + + view-timeline-name: --a-name; + animation-timeline: --a-name; +} +``` + +We applied the animation **before** the animation timeline, as the `animation` resets the `animation-timeline` to `auto`. + +The animation is slightly different from the previous examples in that the spinning effect starts at `20%` and ends at `80%` of the way through the animation; this means the element will not be actively spinning when it first comes into view and will stop spinning before it is completely out of view. + +```css live-sample___named_view live-sample___anon_view +@keyframes action { + 0%, + 20% { + rotate: 45deg; + } + 80%, + 100% { + rotate: 720deg; + } +} +``` + +```css hidden live-sample___named_view live-sample___anon_view live-sample___anon_view_args +.scroller { + width: 400px; + height: 200px; + line-height: 2; + overflow: scroll; + border: 1px solid; + background-color: palegoldenrod; +} +.item { + --size: 50px; + height: var(--size); + width: var(--size); + background-color: magenta; + border: 1px solid; + left: calc(50% - (var(--size) / 2)); + top: calc(50% - (var(--size) / 2)); +} +``` + +```html hidden live-sample___named_view live-sample___anon_view live-sample___anon_view_args +
+

Scroll down to view the animation

+

 

+

 

+

 

+
+

 

+

 

+

 

+

 

+

Scroll up to view the animation

+
+``` + +{{EmbedLiveSample("named_view", "100%", "250")}} + +Scroll the element into view. Note that the element animates through the `@keyframes` animation as it moves through the visible area of its ancestor scroller. + +### Anonymous view progress timeline: the `view()` function + +Alternatively, a {{cssxref("animation-timeline/view", "view()")}} function can be set as the value of the `animation-timeline` property to specify that an element's animation timeline is an _anonymous view progress timeline_. This causes the element to be animated based on its position inside its nearest parent scroller. + +The `view()` function creates a view timeline. You attach the timeline to the element you want to animate using the `animation-timeline` property. The function creates a view timeline for each element matched by the selector. + +In this example, we again define the `animation` before the `animation-timeline`, so the timeline is not reset. We then include an argument-less `view()` function. We don't specify a scroller, as, by definition, the subject's visibility is tracked by its nearest ancestor scroller. + +```css live-sample___anon_view +.item { + animation: action 1ms linear; + animation-timeline: view(); +} +``` + +{{EmbedLiveSample("anon_view", "100%", "250")}} + +### Parameters of the `view()` function + +The `view()` function takes up to three optional values as arguments: + +- Zero or one `` parameters. If set, this specifies the scroll axis along which the animation progresses. +- Either the keyword `auto` or zero, one, or two {{cssxref("length-percentage")}} inset values. If set, these values specify offsets for the scrollport start and/or end. + +Declaring `view()` is equivalent to `view(block auto)`, which defines `block` as the axis of the parent element that supplies the timeline and the {{cssxref("scroll-padding")}}, which generally defaults to `0`, as the insets within the visible area at which the animation starts and ends. + +The function sets the values of the {{cssxref("view-timeline-axis")}} and {{cssxref("view-timeline-inset")}} properties. + +The {{cssxref("view-timeline-inset")}} arguments specify insets (if positive) or outsets (if negative) that adjust the start and end of the scrollport. They are used to determine the scroll positions at which the element is considered "in view", which determines the length of the animation timeline. In other words, instead of starting at the start edge and ending at the end edge of the scrollport, the animation occurs at the start and end of the inset-adjusted view. + +Unlike the scroll timeline's `scroll()` function, there is no `` argument in the `view()` function, as the view timeline always tracks the subject within its nearest ancestor scroll container. + +In this example, as we are using inset values, we can use the `from` and `to` keyframe selectors. + +```css live-sample___anon_view_args +@keyframes action { + from { + rotate: 45deg; + } + to { + rotate: 720deg; + } +} + +.item { + animation: action 1ms linear; + animation-timeline: view(block 20% 20%); +} +``` + +{{EmbedLiveSample("anon_view_args", "100%", "250")}} + +## Accessibility concerns + +As with all animations and transitions, always take any user's [`prefers-reduced-motion`](/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion) preference into account. + +### Removing an animation's timeline + +Setting `animation-timeline: none` disassociates the element from all animation timelines, including the default time-based document timeline, meaning the element will not animate. While some animations may be necessary, you can remove animations based on the user's `prefers-reduced-motion` setting with: + +```css +@media (prefers-reduced-motion: reduce) { + .optionalAnimations { + animation-timeline: none; + } +} +``` + +Because the `animation` shorthand sets the `animation-timeline` to `auto`, use a selector with enough specificity to ensure your `animation-timeline` isn't overridden by your `animation` shorthand declarations. + +## See also + +- [CSS animations](/en-US/docs/Web/CSS/Guides/Animations) +- [Web Animations API](/en-US/docs/Web/API/Web_Animations_API) From 12d15bd3b8670720e007744491490464edd56b1f Mon Sep 17 00:00:00 2001 From: mao-sz <122839503+mao-sz@users.noreply.github.com> Date: Thu, 27 Nov 2025 12:49:58 +0000 Subject: [PATCH 04/21] fix: Remove flex from CSS `writing-mode` example container (#42142) fix: remove flex from example elements Flex interfering with writing-mode behaviour Co-authored-by: Brian Smith --- files/en-us/web/css/reference/properties/writing-mode/index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/files/en-us/web/css/reference/properties/writing-mode/index.md b/files/en-us/web/css/reference/properties/writing-mode/index.md index 478a7f37a5d672f..d733e6d48318126 100644 --- a/files/en-us/web/css/reference/properties/writing-mode/index.md +++ b/files/en-us/web/css/reference/properties/writing-mode/index.md @@ -47,14 +47,12 @@ writing-mode: sideways-lr; padding: 0.75em; width: 80%; max-height: 300px; - display: flex; } #example-element > div { background-color: rgb(0 0 255 / 0.2); border: 3px solid blue; margin: 10px; - flex: 1; } ``` From a7de1aac32b2d1eb272248efb8734877698ee6e3 Mon Sep 17 00:00:00 2001 From: Menci Date: Thu, 27 Nov 2025 21:06:20 +0800 Subject: [PATCH 05/21] docs(headers): clarify quotes requirement in Content-Disposition of multipart/form-data (#42065) * docs(headers): clarify quotes requirement in Content-Disposition of multipart/form-data * Update files/en-us/web/http/reference/headers/content-disposition/index.md * Update files/en-us/web/http/reference/headers/content-disposition/index.md --------- Co-authored-by: Hamish Willee --- .../http/reference/headers/content-disposition/index.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/http/reference/headers/content-disposition/index.md b/files/en-us/web/http/reference/headers/content-disposition/index.md index b059d061f18915d..e0035dd018b61e9 100644 --- a/files/en-us/web/http/reference/headers/content-disposition/index.md +++ b/files/en-us/web/http/reference/headers/content-disposition/index.md @@ -55,7 +55,12 @@ Browsers may apply transformations to conform to the file system requirements, s ### As a header for a multipart body -A `multipart/form-data` body requires a `Content-Disposition` header to provide information about each subpart of the form (e.g., for every form field and any files that are part of field data). The first directive is always `form-data`, and the header must also include a `name` parameter to identify the relevant field. Additional directives are case-insensitive and have arguments that use quoted-string syntax after the `=` sign. Multiple parameters are separated by a semicolon (`;`). +A `multipart/form-data` body requires a `Content-Disposition` header to provide information about each subpart of the form (e.g., for every form field and any files that are part of field data). +The first directive is always `form-data`, and the header must also include a `name` parameter to identify the relevant field. Additional directives are case-insensitive. +The value of any arguments (after the `=` sign) may be a either token or a quoted string. +Quoted strings are recommended, and many server implementations require the values to be quoted. +This is because a token must be US-ASCII for MIME type headers like `Content-Disposition`, and US-ASCII does not allow some characters that are common in filenames and other values. +Multiple parameters are separated by a semicolon (`;`). ```http Content-Disposition: form-data; name="fieldName" From 78479a685244ee33d77e79b140c5e841d41dff31 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 27 Nov 2025 13:06:37 +0000 Subject: [PATCH 06/21] Improve clarity of sizing task instructions (#42134) Reworded instructions and explanations for clarity and consistency. --- .../test_your_skills/sizing/index.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/files/en-us/learn_web_development/core/styling_basics/test_your_skills/sizing/index.md b/files/en-us/learn_web_development/core/styling_basics/test_your_skills/sizing/index.md index 116867062df7c7d..cb89e3f9a15df84 100644 --- a/files/en-us/learn_web_development/core/styling_basics/test_your_skills/sizing/index.md +++ b/files/en-us/learn_web_development/core/styling_basics/test_your_skills/sizing/index.md @@ -19,9 +19,9 @@ In this task, you have two boxes. To complete the task: -1. Size the first box so that the height will be at least `100px`, even if there is less content that would cause it to grow to that height. However, the content should not overflow if there is more content than fits in 100 pixels. -2. Test this box by removing the content from the HTML to make sure you still get a `100px` tall box even with no content. -3. Size the second box so that it is fixed at `100px` tall, so that content will overflow if there is too much. +1. Size the first box so that the height will be at least `100px`, even if there is less content that would cause it to grow to that height. The content should not overflow if it doesn't fit into the box. +2. To test this, remove the content from the HTML to make sure you still get a `100px` tall box even with no content. +3. Size the second box so that it is fixed at `100px` tall. In this case, the content should overflow. Your final result should look like the image below: @@ -71,7 +71,7 @@ body {
Click here to show the solution -There are two boxes, the first should be given a minimum height, in which case it will expand to take the additional content but if you remove some content, the box will be at least as tall as the `min-height`. The second is given a fixed height which will cause content to overflow. +There are two boxes. The first one should be given a `min-height` so it expands to hold the additional content, but will not shrink below `100px` tall if the content is removed. The second box is given a fixed height, which will cause content to overflow. ```css .box1 { @@ -87,12 +87,12 @@ There are two boxes, the first should be given a minimum height, in which case i ## Task 2 -In this task, you have a box, which contains another box. +In this task, you have a box that contains another box. To complete the task: -1. Make the inner box width `60%` of the width of the outer box. The value of the {{cssxref("box-sizing")}} property is set to `border-box`, which means that the total width includes any padding and border. -2. Give the inner box padding of `10%` using the width (or inline size) as the size from which that percentage is calculated. +1. Make the inner box width `60%` of the width of the outer box. The {{cssxref("box-sizing")}} property is set to `border-box`, which means that the total width includes any `padding` and `border`. +2. Give the inner box `10%` padding on all sides. Your final result should look like the image below: @@ -135,8 +135,8 @@ body {
Click here to show the solution -Make the box 60% of the container and give it 10% of padding on all sides. -All elements already have `box-sizing: border-box` to save you from worrying about which width you are using: +Set the box `width` to `60%`, and give it a `padding` value of `10%`. +All elements already have `box-sizing: border-box` set to save you from worrying about calculating the `60%` width value: ```css * { @@ -152,11 +152,11 @@ All elements already have `box-sizing: border-box` to save you from worrying abo ## Task 3 -In this task, you have two images in boxes. One image is smaller than the box, the other is larger and breaking out of the box. +In this task, you have two images in boxes. One image is smaller than the box, while the other is larger, causing it to break out of the box. -To complete the task, imagine that the box is responsive and therefore could grow and shrink. Apply a declaration to the image so that the large image shrinks down into the box but the small image does not stretch. +To complete the task, imagine that the box is responsive and therefore could grow and shrink. Apply a declaration to the images so that the large image shrinks down into the box, but the small image does not stretch. -Your final result should look like the images below: +Your final result should look like this: ![Two boxes with images in](mdn-sizing-max-width.png) @@ -195,7 +195,7 @@ img {
Click here to show the solution -The example has an image which is breaking out of the box and one which is smaller than the box, you need to use `max-width` set to 100% to cause the larger image to grow only as large as the box. If you use `width: 100%`, the small image will stretch. +Set the images' `max-width` property to `100%` to contain the large image inside its box. If you use `width: 100%`, the small image will stretch. ```css img { From c834e8c8dcf6ad3ef2f90133598aa1e45c39424d Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 27 Nov 2025 17:09:59 +0100 Subject: [PATCH 07/21] chore: Fixes for Prettier 3 7 1 (#42152) --- files/en-us/glossary/character_reference/index.md | 6 +++--- files/en-us/web/css/reference/properties/content/index.md | 3 +-- .../web/css/reference/properties/pointer-events/index.md | 3 +-- .../css/reference/selectors/attribute_selectors/index.md | 6 ++---- .../javascript/reference/statements/import/with/index.md | 4 +++- package.json | 2 +- yarn.lock | 8 ++++---- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/files/en-us/glossary/character_reference/index.md b/files/en-us/glossary/character_reference/index.md index 6e9319e055320f4..17ba10633e31764 100644 --- a/files/en-us/glossary/character_reference/index.md +++ b/files/en-us/glossary/character_reference/index.md @@ -37,9 +37,9 @@ A very small subset of useful named character references along with their unicod | | ` ` | U+000A0 | | – | `–` | U+02013 | | — | `—` | U+02014 | -| © | `©` | U+000A9 | -| ® | `®` | U+000AE | -| ™ | `™` | U+02122 | +| © | `©` | U+000A9 | +| ® | `®` | U+000AE | +| ™ | `™` | U+02122 | | ≈ | `≈` | U+02248 | | ≠ | `≠` | U+02260 | | £ | `£` | U+000A3 | diff --git a/files/en-us/web/css/reference/properties/content/index.md b/files/en-us/web/css/reference/properties/content/index.md index f0305249da9559e..f71a56701ae63f6 100644 --- a/files/en-us/web/css/reference/properties/content/index.md +++ b/files/en-us/web/css/reference/properties/content/index.md @@ -299,8 +299,7 @@ This example is useful for print stylesheets. It uses an [attribute selector](/e #### CSS ```css -a[href^="https://"]::after -{ +a[href^="https://"]::after { content: " (URL: " attr(href) ")"; color: darkgreen; } diff --git a/files/en-us/web/css/reference/properties/pointer-events/index.md b/files/en-us/web/css/reference/properties/pointer-events/index.md index 5f597ad730c021e..21f0d3e2633a8b0 100644 --- a/files/en-us/web/css/reference/properties/pointer-events/index.md +++ b/files/en-us/web/css/reference/properties/pointer-events/index.md @@ -170,8 +170,7 @@ This example disables pointer events on the link to `http://example.com`. #### CSS ```css -a[href="http://example.com"] -{ +a[href="http://example.com"] { pointer-events: none; } ``` diff --git a/files/en-us/web/css/reference/selectors/attribute_selectors/index.md b/files/en-us/web/css/reference/selectors/attribute_selectors/index.md index 88d372c9a51cbb4..08cbfae8db4eef8 100644 --- a/files/en-us/web/css/reference/selectors/attribute_selectors/index.md +++ b/files/en-us/web/css/reference/selectors/attribute_selectors/index.md @@ -17,8 +17,7 @@ a[title] { } /* elements with an href matching "https://example.org" */ -a[href="https://example.org"] -{ +a[href="https://example.org"] { color: green; } @@ -111,8 +110,7 @@ a[href$=".org"] { } /* Links that start with "https://" and end in ".org" */ -a[href^="https://"][href$=".org"] -{ +a[href^="https://"][href$=".org"] { color: green; } ``` diff --git a/files/en-us/web/javascript/reference/statements/import/with/index.md b/files/en-us/web/javascript/reference/statements/import/with/index.md index 273a08708eb0c89..1c3952f1bb09339 100644 --- a/files/en-us/web/javascript/reference/statements/import/with/index.md +++ b/files/en-us/web/javascript/reference/statements/import/with/index.md @@ -87,7 +87,9 @@ The attributes syntax is designed to be extensible — although only `type` is s - Resolution: the attribute is part of the module specifier (the string in the `from` clause). Therefore, given the same string path, different attributes may lead to entirely different modules being loaded. For example, [TypeScript supports the `resolution-mode` attribute](https://devblogs.microsoft.com/typescript/announcing-typescript-5-3/#stable-support-resolution-mode-in-import-types). ```ts - import type { TypeFromRequire } from "pkg" with { "resolution-mode": "require" }; + import type { TypeFromRequire } from "pkg" with { + "resolution-mode": "require", + }; ``` - Fetching: for example, CSS modules are fetched with the [`destination`](/en-US/docs/Web/API/Request/destination) set to `"style"`, and JSON modules are fetched with `destination: "json"`. This means given the same destination URL, the server may still return different content. diff --git a/package.json b/package.json index 501dffca0eec270..072e870b264c95c 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "markdownlint-rule-search-replace": "1.2.0", "node-html-parser": "^7.0.1", "parse-diff": "^0.11.1", - "prettier": "3.6.2", + "prettier": "3.7.1", "tempy": "^3.1.0", "yaml": "^2.8.1", "yargs": "^18.0.0" diff --git a/yarn.lock b/yarn.lock index 17770dcfdc8ef4a..dec9daabbf58b03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4978,10 +4978,10 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prettier@3.6.2, prettier@^3.2.5: - version "3.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" - integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== +prettier@3.7.1, prettier@^3.2.5: + version "3.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.7.1.tgz#8dfbf54c98e85a113962d3d8414ae82ff3722991" + integrity sha512-RWKXE4qB3u5Z6yz7omJkjWwmTfLdcbv44jUVHC5NpfXwFGzvpQM798FGv/6WNK879tc+Cn0AAyherCl1KjbyZQ== pretty-ms@^9.0.0: version "9.2.0" From b94be967a1128c8521185994600ebc097481bf19 Mon Sep 17 00:00:00 2001 From: Youssef Date: Fri, 28 Nov 2025 09:18:41 +0000 Subject: [PATCH 08/21] Use a better equivalent function to an arrow-function example (#42128) * Fix arrow function syntax in example The original provided example is correct, but I think the `arrow function` is literally **equivalent** to an **anonymous function**. * Fix syntax * Update files/en-us/learn_web_development/core/scripting/functions/index.md Co-authored-by: Chris Mills * Update files/en-us/learn_web_development/core/scripting/functions/index.md Co-authored-by: Chris Mills * Refactor map function to use the anynomous function syntax Refactor map function to use arrow function syntax. * Fix a syntax error * Replace terminal period with colon * Correct arrow function syntax in event listener example Fix syntax error in the arrow function example for addEventListener. * Add nolint to problem code block, grammar nits --------- Co-authored-by: Joshua Chen Co-authored-by: Chris Mills --- .../core/scripting/functions/index.md | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/files/en-us/learn_web_development/core/scripting/functions/index.md b/files/en-us/learn_web_development/core/scripting/functions/index.md index 0798105068086c3..54e3b6964f0d38b 100644 --- a/files/en-us/learn_web_development/core/scripting/functions/index.md +++ b/files/en-us/learn_web_development/core/scripting/functions/index.md @@ -36,13 +36,13 @@ Another essential concept in coding is **functions**, which allow you to store a ## Where do I find functions? -In JavaScript, you'll find functions everywhere. In fact, we've been using functions all the way through the course so far; we've just not been talking about them very much. Now is the time, however, for us to start talking about functions explicitly, and really exploring their syntax. +In JavaScript, you'll find functions everywhere. In fact, we've been using functions throughout the course so far; we've just not been talking about them very much. Now is the time, however, for us to start talking about functions explicitly and exploring their syntax. Pretty much anytime you make use of a JavaScript structure that features a pair of parentheses — `()` — and you're **not** using a common built-in language structure like a [for loop](/en-US/docs/Learn_web_development/Core/Scripting/Loops#the_standard_for_loop), [while or do...while loop](/en-US/docs/Learn_web_development/Core/Scripting/Loops#while_and_do...while), or [if...else statement](/en-US/docs/Learn_web_development/Core/Scripting/Conditionals#if...else_statements), you are making use of a function. ## Built-in browser functions -We've used functions built into the browser a lot in this course. +We've made extensive use of built-in browser functions in this course. Every time we manipulated a text string, for example: @@ -79,15 +79,15 @@ We were using a _function_! > [!NOTE] > Feel free to enter these lines into your browser's JavaScript console to re-familiarize yourself with their functionality, if needed. -The JavaScript language has many built-in functions to allow you to do useful things without having to write all that code yourself. In fact, some of the code you are calling when you **invoke** (a fancy word for run, or execute) a built-in browser function couldn't be written in JavaScript — many of these functions are calling parts of the background browser code, which is written largely in low-level system languages like C++, not web languages like JavaScript. +The JavaScript language has many built-in functions that allow you to do useful things without having to write all that code yourself. In fact, some of the code you are calling when you **invoke** (a fancy word for run, or execute) a built-in browser function couldn't be written in JavaScript — many of these functions are calling parts of the background browser code, which is written largely in low-level system languages like C++, not web languages like JavaScript. Bear in mind that some built-in browser functions are not part of the core JavaScript language — some are defined as part of browser APIs, which build on top of the default language to provide even more functionality (refer to [this early section of our course](/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript#so_what_can_it_really_do) for more descriptions). We'll look at using browser APIs in more detail in a later module. ## Functions versus methods -**Functions** that are part of objects are called **methods**; you'll learn about objects later in the module. For now, we just wanted to clear up any possible confusion about method versus function — you are likely to meet both terms as you look at the available related resources across the Web. +**Functions** that are part of objects are called **methods**; you'll learn about objects later in the module. For now, we just wanted to clear up any possible confusion about method versus function — you are likely to meet both terms as you look at related resources across the Web. -The built-in code we've made use of so far comes in both forms: **functions** and **methods.** You can check the full list of the built-in functions, as well as the built-in objects and their corresponding methods [in our JavaScript reference](/en-US/docs/Web/JavaScript/Reference/Global_Objects). +The built-in code we've used so far comes in both forms: **functions** and **methods.** You can check the full list of built-in functions, as well as built-in objects and their corresponding methods [in our JavaScript reference](/en-US/docs/Web/JavaScript/Reference/Global_Objects). You've also seen a lot of **custom functions** in the course so far — functions defined in your code, not inside the browser. Anytime you saw a custom name with parentheses straight after it, you were using a custom function. In our [random-canvas-circles.html](https://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html) example (see also the full [source code](https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/loops/random-canvas-circles.html)) from our [loops article](/en-US/docs/Learn_web_development/Core/Scripting/Loops), we included a custom `draw()` function that looked like this: @@ -103,13 +103,13 @@ function draw() { } ``` -This function draws 100 random circles inside a {{htmlelement("canvas")}} element. Every time we want to do that, we can just invoke the function with this: +This function draws 100 random circles inside a {{htmlelement("canvas")}} element. Every time we want to do that, we can invoke the function with this: ```js draw(); ``` -rather than having to write all that code out again every time we want to repeat it. Functions can contain whatever code you like — you can even call other functions from inside functions. The above function for example calls the `random()` function three times, which is defined by the following code: +rather than having to write all that code out again every time we want to repeat it. Functions can contain whatever code you like — you can even call other functions from inside functions. The above function, for example, calls the `random()` function three times, which is defined by the following code: ```js function random(number) { @@ -121,7 +121,7 @@ We needed this function because the browser's built-in [`Math.random()`](/en-US/ ## Invoking functions -You are probably clear on this by now, but just in case, to actually use a function after it has been defined, you've got to run — or invoke — it. This is done by including the name of the function in the code somewhere, followed by parentheses. +You are probably clear on this by now, but just in case, to actually use a function after it has been defined, you've got to run — or invoke — it. This is done by including the function's name in the code somewhere, followed by parentheses. ```js function myFunction() { @@ -137,7 +137,7 @@ myFunction(); ## Function parameters -Some functions require **parameters** to be specified when you are invoking them — these are values that need to be included inside the function parentheses, which it needs to do its job properly. +Some functions require **parameters** to be specified when you invoke them — these are values that need to be included inside the function parentheses, which it needs to do its job properly. > [!NOTE] > Parameters are sometimes called arguments, properties, or even attributes. @@ -156,11 +156,11 @@ const newString = myText.replace("string", "sausage"); ``` > [!NOTE] -> When you need to specify multiple parameters, they are separated by commas. +> When you need to specify multiple parameters, you separate them with commas. ### Optional parameters -Sometimes parameters are optional — you don't have to specify them. If you don't, the function will generally adopt some kind of default behavior. As an example, the array [`join()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) function's parameter is optional: +Sometimes parameters are optional — you don't have to specify them. If you don't, the function generally adopts some kind of default behavior. As an example, the array [`join()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) function's parameter is optional: ```js const myArray = ["I", "love", "chocolate", "frogs"]; @@ -190,7 +190,7 @@ hello(); // Hello Chris! ## Anonymous functions and arrow functions -So far we have just created a function like so: +So far, we have just created functions like so: ```js function myFunction() { @@ -213,12 +213,12 @@ This is called an **anonymous function**, because it has no name. You'll often s ### Anonymous function example -For example, let's say you want to run some code when the user types into a text box. To do this you can call the {{domxref("EventTarget/addEventListener", "addEventListener()")}} function of the text box. This function expects you to pass it (at least) two parameters: +For example, let's say you want to run some code when the user types into a text box. To do this, you can call the {{domxref("EventTarget/addEventListener", "addEventListener()")}} function of the text box. This function expects you to pass it at least two parameters: -- the name of the event to listen for, which in this case is {{domxref("Element/keydown_event", "keydown")}} -- a function to run when the event happens. +- The name of the event to listen for, which in this case is {{domxref("Element/keydown_event", "keydown")}} +- A function to run when the event happens. -When the user presses a key, the browser will call the function you provided, and will pass it a parameter containing information about this event, including the particular key that the user pressed: +When the user presses a key, the browser will call the function you provided, and pass it a parameter containing information about this event, including the particular key that the user pressed: ```js function logKey(event) { @@ -264,34 +264,34 @@ const doubled = originals.map(item => item * 2); console.log(doubled); // [2, 4, 6] ``` -The `map()` method takes each item in the array in turn, passing it into the given function. It then takes the value returned by that function and adds it to a new array. +The `map()` method passes each item in the array into the given function, then takes the value returned by the function and adds it to a new array. -So in the example above, `item => item * 2` is the arrow function equivalent of: +The arrow function is very concise; rewriting our `map()` code to use a regular anonymous callback function would look like this: ```js -function doubleItem(item) { +const doubled = originals.map(function (item) { return item * 2; -} +}); ``` -You can use the same concise syntax to rewrite the `addEventListener` example. +You can use the same concise arrow function syntax to rewrite the `addEventListener()` example: -```js +```js-nolint textBox.addEventListener("keydown", (event) => - console.log(`You pressed "${event.key}".`), + console.log(`You pressed "${event.key}".`) ); ``` In this case, the value of `console.log()`, which is `undefined`, is implicitly returned from the callback function. -We recommend that you use arrow functions, as they can make your code shorter and more readable. To learn more, see the [section on arrow functions in the JavaScript guide](/en-US/docs/Web/JavaScript/Guide/Functions#arrow_functions), and our [reference page on arrow functions](/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). +We recommend using arrow functions, as they can make your code shorter and more readable. To learn more, see the [section on arrow functions in the JavaScript guide](/en-US/docs/Web/JavaScript/Guide/Functions#arrow_functions), and our [reference page on arrow functions](/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). > [!NOTE] > There are some subtle differences between arrow functions and normal functions. They're outside the scope of this introductory tutorial and are unlikely to make a difference in the cases we've discussed here. To learn more, see the [arrow function reference documentation](/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). ### Arrow function live sample -Here's a complete working example of the "keydown" example we discussed above: +Here's a complete working version of the `keydown` example we discussed above: The HTML: @@ -323,11 +323,11 @@ The result - try typing into the text box and see the output: ## Function scope and conflicts -Let's talk a bit about {{glossary("scope")}} — a very important concept when dealing with functions. When you create a function, the variables and other things defined inside the function are inside their own separate **scope**, meaning that they are locked away in their own separate compartments, unreachable from code outside the functions. +Let's talk a bit about {{glossary("scope")}} — an important concept when dealing with functions. When you create a function, the variables and other things defined inside the function are inside their own separate **scope**. This means that they are locked away in their own separate compartment, unreachable from code outside the functions. The top-level outside all your functions is called the **global scope**. Values defined in the global scope are accessible from everywhere in the code. -JavaScript is set up like this for various reasons — but mainly because of security and organization. Sometimes you don't want variables to be accessible from everywhere in the code. External scripts that you call in from elsewhere could start to mess with your code and cause problems because they happen to be using the same variable names as other parts of the code, causing conflicts. This might be done maliciously, or just by accident. +JavaScript works like this mainly for security and organization. Sometimes you don't want variables to be accessible from everywhere in the code. External scripts called in from elsewhere could start to mess with your code and cause problems if they use the same variable names, causing conflicts. This might be done maliciously or just by accident. For example, say you have an HTML file referencing two external JavaScript files, and both of them have a variable and a function defined that use the same name: @@ -362,11 +362,11 @@ You can see this example [running live on GitHub](https://mdn.github.io/learning - The second script, however, does not load and run at all, and an error is printed in the console: `Uncaught SyntaxError: Identifier 'name' has already been declared`. This is because the `name` constant is already declared in `first.js`, and you can't declare the same constant twice in the same scope. Because the second script did not load, the `greeting()` function from `second.js` is not available to be called. -- If we were to remove the `const name = "Zaptec";` line from `second.js` and reload the page, both scripts would execute. The alert box would now say `Our company is called Chris.` Functions _can_ be redeclared, and the last declaration in the source order is used. The previous declarations are effectively overwritten. +- If we were to remove the `const name = "Zaptec";` line from `second.js` and reload the page, both scripts would execute. The alert box would now say `Our company is called Chris.` If a function is _redeclared_, the last declaration in the source order is used. The previous declarations are effectively overwritten. -Keeping parts of your code locked away in functions avoids such problems, and is considered a best practice. +Locking parts of your code away in functions avoids such problems and is considered a best practice. -It is a bit like a zoo. The lions, zebras, tigers, and penguins are kept in their own enclosures and only have access to the things inside — in the same manner as the function scopes. If they were able to get into other enclosures, problems would occur. At best, different animals would feel really uncomfortable inside unfamiliar habitats — a lion or tiger would feel terrible inside the penguins' watery, icy domain. At worst, the lions and tigers might try to eat the penguins! +It is a bit like a zoo. The lions, zebras, tigers, and penguins are kept in their own enclosures and only have access to the things inside, similar to function scopes. If they were able to get into other enclosures, problems would occur. At best, different animals would feel really uncomfortable inside unfamiliar habitats — a lion or tiger would feel terrible inside the penguins' watery, icy domain. At worst, the lions and tigers might try to eat the penguins! ![Four different animals enclosed in their respective habitat in a Zoo](mdn-mozilla-zoo.png) @@ -376,7 +376,7 @@ The zoo keeper is like the global scope — they have the keys to access every e Let's look at a real example to demonstrate scoping. -1. First, make a local copy of our [function-scope.html](https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/function-scope.html) example. This contains two functions called `a()` and `b()`, and three variables — `x`, `y`, and `z` — two of which are defined inside the functions, and one in the global scope. It also contains a third function called `output()`, which takes a single parameter and outputs it in a paragraph on the page. +1. First, make a local copy of our [function-scope.html](https://github.com/mdn/learning-area/blob/main/javascript/building-blocks/functions/function-scope.html) example. This contains two functions called `a()` and `b()`, and three variables — `x`, `y`, and `z` — two of which are defined inside the functions, and one in the global scope. It also contains a third function called `output()`, which takes a single parameter and outputs it to a paragraph on the page. 2. Open the example up in a browser and in your text editor. 3. Open the JavaScript console in your browser developer tools. In the JavaScript console, enter the following command: @@ -416,7 +416,7 @@ Let's look at a real example to demonstrate scoping. b(); ``` - You should see the `y` and `z` values printed in the browser viewport. This works fine, as the `output()` function is being called inside the other functions, in the same scope as the variables it is printing are defined in. `output()` itself is available from anywhere, as it is defined in the global scope. + You should see the `y` and `z` values printed in the browser viewport. This works fine, as the `output()` function is called inside the other functions, in the same scope as the variables it prints are defined in. `output()` itself is available from anywhere, as it is defined in the global scope. 6. Now try updating your code like this: @@ -439,7 +439,7 @@ Let's look at a real example to demonstrate scoping. b(); ``` - Both the `a()` and `b()` call should print the value of x to the browser viewport. These work fine because even though the `output()` calls are not in the same scope as `x` is defined in, `x` is a global variable so is available inside all code, everywhere. + Both the `a()` and `b()` calls should print the value of x to the browser viewport. These work fine because even though the `output()` calls are not in the same scope as `x` is defined in, `x` is a global variable — it is available inside all code, everywhere. 8. Finally, try updating your code like this: @@ -472,7 +472,7 @@ Let's look at a real example to demonstrate scoping. ## Summary -This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function. +This article has explored the fundamental concepts behind functions, paving the way for the next one, in which we get practical and take you through the steps to build your own custom function. ## See also From 5078baa9da0c242ee4a453af749a7c96e80e6270 Mon Sep 17 00:00:00 2001 From: Estelle Weyl Date: Fri, 28 Nov 2025 10:28:30 +0100 Subject: [PATCH 09/21] background-repeat x and y (#42153) Updated background-repeat references to include background-repeat-x and background-repeat-y as supported, because Safari does support these two properties --- files/en-us/web/css/guides/backgrounds_and_borders/index.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/files/en-us/web/css/guides/backgrounds_and_borders/index.md b/files/en-us/web/css/guides/backgrounds_and_borders/index.md index b44471ceee44d1e..d03a4785d96ad57 100644 --- a/files/en-us/web/css/guides/backgrounds_and_borders/index.md +++ b/files/en-us/web/css/guides/backgrounds_and_borders/index.md @@ -27,7 +27,9 @@ The properties in this module also let you define whether cells inside a {{HTMLE - {{cssxref("background-image")}} - {{cssxref("background-origin")}} - {{cssxref("background-position")}} -- {{cssxref("background-repeat")}} +- {{cssxref("background-repeat-x")}} +- {{cssxref("background-repeat-y")}} +- {{cssxref("background-repeat")}} shorthand - {{cssxref("background-size")}} - {{cssxref("background")}} shorthand - {{cssxref("background-position-x")}} @@ -65,7 +67,7 @@ The properties in this module also let you define whether cells inside a {{HTMLE - {{cssxref("border-image")}} shorthand - {{cssxref("box-shadow")}} -The CSS backgrounds module level 4 also introduces the `background-position-block`, `background-position-inline`, `background-repeat-block`, `background-repeat-inline`, `background-repeat-x`, `background-repeat-y`, and `background-tbd` properties. Currently, no browsers support these features. +The CSS backgrounds module level 4 also introduces the `background-position-block`, `background-position-inline`, `background-repeat-block`, `background-repeat-inline`, and `background-tbd` properties. Currently, no browsers support these features. ### Data types From e84cf88043b5f2216d4d354e1dbea11cca049ad6 Mon Sep 17 00:00:00 2001 From: Estelle Weyl Date: Fri, 28 Nov 2025 10:31:07 +0100 Subject: [PATCH 10/21] Revise CSS timeline-scope property (#42118) * Revise CSS timeline-scope property Updated the documentation for the `timeline-scope` CSS property to enhance clarity and consistency. Improved examples and descriptions related to timeline scope and its usage. * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update files/en-us/web/css/reference/properties/timeline-scope/index.md Co-authored-by: Brian Smith --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Brian Smith --- .../properties/timeline-scope/index.md | 81 ++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/files/en-us/web/css/reference/properties/timeline-scope/index.md b/files/en-us/web/css/reference/properties/timeline-scope/index.md index 738f9f68ddac15c..7233b888e7acb0b 100644 --- a/files/en-us/web/css/reference/properties/timeline-scope/index.md +++ b/files/en-us/web/css/reference/properties/timeline-scope/index.md @@ -8,18 +8,23 @@ sidebar: cssref The **`timeline-scope`** [CSS](/en-US/docs/Web/CSS) property modifies the scope of a named animation timeline. -By default, a named timeline (i.e., declared using {{cssxref("scroll-timeline-name")}} or {{cssxref("view-timeline-name")}}) can only be set as the controlling timeline of a direct descendant element (i.e., by setting {{cssxref("animation-timeline")}} on it with the timeline name as its value). This is the timeline's default "scope". - -`timeline-scope` is given the name of a timeline defined on a descendant element; this causes the scope of the timeline to be increased to the element that `timeline-scope` is set on and any of its descendants. In other words, that element and any of its descendant elements can now be controlled using that timeline. - -> [!NOTE] -> If no timeline (or more than one timeline) exists with the name given for the `timeline-scope` value, an inactive timeline with the specified name is created. - ## Syntax ```css +/* Keyword values */ +timeline-scope: all; timeline-scope: none; -timeline-scope: custom_name_for_timeline; + +/* Custom name values */ +timeline-scope: --custom_name_for_timeline; +timeline-scope: --timeline_name_one, --timeline_name_two; + +/* Global values */ +timeline-scope: inherit; +timeline-scope: initial; +timeline-scope: revert; +timeline-scope: revert-layer; +timeline-scope: unset; ``` ### Values @@ -27,12 +32,19 @@ timeline-scope: custom_name_for_timeline; Allowed values for `timeline-scope` are: - `none` - - : There is no change in timeline scope. + - : There is no change in timeline scope. This is the default. +- `all` + - : The names of all timelines defined by descendants are in scope for this element and its descendants. - `` - - : Specifies the name of an existing named timeline (i.e., declared using {{cssxref("scroll-timeline-name")}} or {{cssxref("view-timeline-name")}}) defined on a descendant element. This causes the timeline scope to be increased to the element that `timeline-scope` is set on and any of its descendants. + - : Specifies the name of an existing named timeline (i.e., declared using {{cssxref("scroll-timeline-name")}} or {{cssxref("view-timeline-name")}}) defined on a descendant element. This increases the timeline scope to the current element and to any of its descendants. + +## Description + +The `timeline-scope` property modifies the scope of a named animation timeline. By default, a [named timeline](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines#animation_timelines) (i.e., declared using {{cssxref("scroll-timeline-name")}} or {{cssxref("view-timeline-name")}}) can only be set as the controlling timeline of a direct descendant element (i.e., by setting {{cssxref("animation-timeline")}} on it with the timeline name as its value). This is the default "scope" for the timeline. - > [!NOTE] - > [``](/en-US/docs/Web/CSS/Reference/Values/custom-ident) values must start with `--`, which helps to avoid name clashes with standard CSS keywords. +The value of the `timeline-scope` is the name of a timeline defined on a descendant element; this changes the scope of the timeline to include the targeted element and its descendants. In other words, that element on which the `timeline-scope` property is defined, and all of its descendant elements, can be controlled using that timeline. + +If no timeline (or more than one timeline) exists with the name given for the `timeline-scope` value, an inactive timeline with the specified name is created. The `timeline-scope` property only works with named timelines, and therefore can not be used in conjunction with anonymous timelines created using the {{cssxref("view()")}} or {{cssxref("scroll()")}} animation timeline functions. ## Formal definition @@ -44,11 +56,11 @@ Allowed values for `timeline-scope` are: ## Examples -In this example, a scroll timeline named `--my-scroller` is defined using the `scroll-timeline-name` property on the element with the `scroller` class (the scrolling element). This is then applied to the animation on the element with the `box` and `animation` classes (the animated element) using `animation-timeline: --my-scroller`. The key point to note here is that the animated element is not a descendant of the scrolling element — to make this work, we increase the scope of the `--my-scroller` timeline by setting `timeline-scope: --my-scroller` on the {{htmlelement("body")}}. +In this example, we animated an element in response to the scrolling of another element by increasing the timeline scope with the `timeline-scope` property. ### HTML -The HTML for the example is shown below. +The HTML includes an element to animate and an element to scroll: ```html
@@ -62,9 +74,9 @@ The HTML for the example is shown below. ### CSS -The CSS is as follows. +A scroll timeline named `--my-scroller` is defined using the {{cssxref("scroll-timeline-name")}} property on a scrolling element. This scroll timeline name is used in two other places: it is applied as the {{cssxref("animation-timeline")}} on the element we want to animate, and as `timeline-scope` on an ancestor of both the scroller and the animated element, increasing the scope. -First of all, we set the ``'s height to `100vh`, and lay its two child elements out as two equal columns using flexbox. We also set `timeline-scope: --my-scroller` on it so that the `--my-scroller` timeline can be set as the controlling timeline for an animation set on the `` and any element inside it. +We set the ``'s height to `100vh`, and lay its two child elements out as two equal columns using flexbox. To increase the timeline scope from the `
` element to the whole ``, we set `timeline-scope: --my-scroller` on it. By doing so, the `--my-scroller` timeline can be set as the controlling timeline for an animation set on the `` or any element nested inside it. ```css body { @@ -72,8 +84,6 @@ body { height: 100vh; display: flex; - /* increases the timeline scope from the .scroller
element - to the whole */ timeline-scope: --my-scroller; } @@ -83,7 +93,7 @@ body { } ``` -Next, the scrolling element has the `--my-scroller` timeline set on it, `overflow` so that it will scroll, and it is given a background color so that its boundary is clear to see. The scrolling element's child long element is given a large height so that the scrolling element will actually scroll. +We set `--my-scroller` as the {{cssxref("scroll-timeline-name")}} on the scrolling element that should provide the scroll progress timeline for our animated element. We add {{cssxref("overflow")}} to enable scrolling, adding a background color to make its boundary visible. We set a large {{cssxref("height")}} on the contents of our scrolling element so the element actually scrolls. ```css .scroller { @@ -97,7 +107,7 @@ Next, the scrolling element has the `--my-scroller` timeline set on it, `overflo } ``` -Next, we give the animated element some rudimentary styling, and apply an animation to it. We also apply the `--my-scroller` timeline to it using `animation-timeline: --my-scroller`. To reiterate, this is only possible because earlier we set `timeline-scope: --my-scroller` on the `` element — the animated element is **not** a descendant of the scrolling element. +Next, we give the animated element some rudimentary styles and apply an animation to it using the {{cssxref("animation")}} shorthand property. We set the {{cssxref("animation-timeline")}} to the named scroll timeline: `--my-scroller`. To reiterate, animating the element based on the scroll progress of it's cousin element is only possible because we set `timeline-scope` on a mutual ancestor; the animated element is **not** a descendant of the scrolling element. ```css .box { @@ -105,25 +115,36 @@ Next, we give the animated element some rudimentary styling, and apply an animat height: 100px; border-radius: 10px; background-color: rebeccapurple; - position: fixed; - top: 20px; - left: 0%; } .animation { - animation: rotate-appear; + animation: rotate-appear 1ms linear; animation-timeline: --my-scroller; } @keyframes rotate-appear { from { rotate: 0deg; - left: 0%; + translate: 0; } to { rotate: 720deg; - left: 100%; + translate: 100%; + } +} +``` + +```css hidden +@layer supports { + @supports not (timeline-scope: none) { + body::before { + content: "Your browser does not support the 'timeline-scope' property."; + background-color: wheat; + display: block; + text-align: center; + padding: 1rem; + } } } ``` @@ -134,6 +155,8 @@ Scroll the vertical bar on the pink area to see the square animate. {{EmbedLiveSample("Examples", "100%", "320px")}} +The key point to note here is that the animated element is not a descendant of the scrolling element — to make this work, we increase the scope of the `--my-scroller` timeline by setting `timeline-scope: --my-scroller` on the {{htmlelement("body")}}. + ## Specifications {{Specifications}} @@ -144,7 +167,7 @@ Scroll the vertical bar on the pink area to see the square animate. ## See also -- [`animation-timeline`](/en-US/docs/Web/CSS/Reference/Properties/animation-timeline) -- [`scroll-timeline`](/en-US/docs/Web/CSS/Reference/Properties/scroll-timeline), [`scroll-timeline-name`](/en-US/docs/Web/CSS/Reference/Properties/scroll-timeline-name) -- [`view-timeline`](/en-US/docs/Web/CSS/Reference/Properties/view-timeline), [`view-timeline-name`](/en-US/docs/Web/CSS/Reference/Properties/view-timeline-name) +- {{cssxref("animation-timeline")}} +- {{cssxref("scroll-timeline")}}, {{cssxref("scroll-timeline-name")}} +- {{cssxref("view-timeline")}}, {{cssxref("view-timeline-name")}} - [CSS scroll-driven animations](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations) From 3751adffba5246f57039308150d1e56cdcb810ce Mon Sep 17 00:00:00 2001 From: Iaroslav Solovev Date: Fri, 28 Nov 2025 01:34:00 -0800 Subject: [PATCH 11/21] Add useful reference links to the MDN docs (#42154) * Add useful reference links to to MDN docs Most of the function names on this page contained links in them, while some lacked it. I added the missing links so that it is easier for the users to access the docs for the referenced functions. * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Estelle Weyl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../core/styling_basics/values_and_units/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/en-us/learn_web_development/core/styling_basics/values_and_units/index.md b/files/en-us/learn_web_development/core/styling_basics/values_and_units/index.md index 7b6522b536846d9..aa4383fc5955c74 100644 --- a/files/en-us/learn_web_development/core/styling_basics/values_and_units/index.md +++ b/files/en-us/learn_web_development/core/styling_basics/values_and_units/index.md @@ -551,11 +551,11 @@ Try changing the alpha channel values to see how it affects the color output. ### Using hues to specify a color -If you want to go beyond keywords, hexadecimal, and `rgb()` for colors, you might want to try using [``](/en-US/docs/Web/CSS/Reference/Values/hue). +If you want to go beyond keywords, hexadecimal, and [`rgb()`](/en-US/docs/Web/CSS/Reference/Values/color_value/rgb) for colors, you might want to try using [``](/en-US/docs/Web/CSS/Reference/Values/hue). Hue is the value type that allows us to tell the difference or similarity between colors like red, orange, yellow, green, blue, etc. The key concept is that you can specify a hue in an [``](/en-US/docs/Web/CSS/Reference/Values/angle) because most of the color models describe hues using a {{glossary("color wheel")}}. -There are several color functions that include a [``](/en-US/docs/Web/CSS/Reference/Values/hue) component, including `hsl()`, `hwb()`, and [`lch()`](/en-US/docs/Web/CSS/Reference/Values/color_value/lch). Other color functions, like [`lab()`](/en-US/docs/Web/CSS/Reference/Values/color_value/lab), define colors based on what humans can see. +There are several color functions that include a [``](/en-US/docs/Web/CSS/Reference/Values/hue) component, including [`hsl()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hsl), [`hwb()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hwb), and [`lch()`](/en-US/docs/Web/CSS/Reference/Values/color_value/lch). Other color functions, like [`lab()`](/en-US/docs/Web/CSS/Reference/Values/color_value/lab), define colors based on what humans can see. If you want to find out more about these functions and color spaces, see the [Applying color to HTML elements using CSS](/en-US/docs/Web/CSS/Guides/Colors/Applying_color) guide, the [``](/en-US/docs/Web/CSS/Reference/Values/color_value) reference that lists all the different ways you can use colors in CSS, and the [CSS color module](/en-US/docs/Web/CSS/Guides/Colors) that provides an overview of all the color types in CSS and the properties that use color values. @@ -570,14 +570,14 @@ The three parts are: ### HSL -Similar to the `hwb()` function is the [`hsl()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hsl) function, which also specifies an `srgb()` color. +Similar to the [`hwb()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hwb) function is the [`hsl()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hsl) function, which also specifies an `srgb()` color. HSL uses `Hue`, in addition to `Saturation` and `Lightness`: - **Hue**: Again, this represents the base shade of the color. - **Saturation**: How saturated is the color? This takes a value from `0`–`100%`, where `0` is no color (it will appear as a shade of grey), and `100%` is full color saturation. - **Lightness**: How light or bright is the color? This takes a value from `0`–`100%`, where `0` is no light (it will appear completely black) and `100%` is full light (it will appear completely white). -The `hsl()` color value also has an optional fourth value, separated from the color with a slash (`/`), representing the alpha transparency. +The [`hsl()`](/en-US/docs/Web/CSS/Reference/Values/color_value/hsl) color value also has an optional fourth value, separated from the color with a slash (`/`), representing the alpha transparency. Let's update the RGB example to use HSL colors instead: From 02d42b389f52c23a2d37e198f5ef8cfb2485b373 Mon Sep 17 00:00:00 2001 From: MDN Web Docs GitHub Bot <108879845+mdn-bot@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:34:57 +0100 Subject: [PATCH 12/21] fix: auto-cleanup by bot (#42156) * chore: auto-fix Markdownlint, Prettier, and front-matter issues * Update files/en-us/web/css/reference/properties/animation-range/index.md * Update files/en-us/web/css/reference/properties/animation-range/index.md --------- Co-authored-by: Estelle Weyl --- .../web/css/reference/properties/animation-range/index.md | 4 ++-- .../web/css/reference/properties/animation-timeline/index.md | 2 +- .../web/css/reference/values/timeline-range-name/index.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/css/reference/properties/animation-range/index.md b/files/en-us/web/css/reference/properties/animation-range/index.md index f4fddef9c6fc48e..9f55f360a9cb6c8 100644 --- a/files/en-us/web/css/reference/properties/animation-range/index.md +++ b/files/en-us/web/css/reference/properties/animation-range/index.md @@ -56,9 +56,9 @@ The `animation-range` shorthand property is specified as one or more single anim ### Values - `` - - : The keyword `normal`, a ``, a [``](/en-US/docs/Web/CSS/Reference/Values/timeline-range-name), or a ` ` pair, representing the [`animation-range-start`](/en-US/docs/Web/CSS/animation-range-start). If a `` is set without a ``, the `` defaults to `0%`. + - : The keyword `normal`, a ``, a [``](/en-US/docs/Web/CSS/Reference/Values/timeline-range-name), or a ` ` pair, representing the {{cssxref("animation-range-start")}}. If a `` is set without a ``, the `` defaults to `0%`. - `` - - : The keyword `normal`, a ``, a ``, or a ` ` pair, representing the [`animation-range-end`](/en-US/docs/Web/CSS/animation-range-end). If a `` is set without a ``, the `` defaults to `100%`. + - : The keyword `normal`, a ``, a ``, or a ` ` pair, representing the {{cssxref("animation-range-end")}}. If a `` is set without a ``, the `` defaults to `100%`. ## Description diff --git a/files/en-us/web/css/reference/properties/animation-timeline/index.md b/files/en-us/web/css/reference/properties/animation-timeline/index.md index 986e5c690ca89c2..fb359f5cf0c6171 100644 --- a/files/en-us/web/css/reference/properties/animation-timeline/index.md +++ b/files/en-us/web/css/reference/properties/animation-timeline/index.md @@ -441,6 +441,6 @@ The `parent` element only becomes visible when that parent is visible, meaning t - {{cssxref("scroll-timeline-name")}}, {{cssxref("scroll-timeline-axis")}}, {{cssxref("scroll-timeline")}} - {{cssxref("view-timeline-name")}}, {{cssxref("view-timeline-axis")}}, {{cssxref("view-timeline")}}, {{cssxref("view-timeline-inset")}} - {{domxref("AnimationTimeline")}} -- [Guide: Using CSS animations](/en-US/docs/Web/CSS/Guides/Animations/Using_CSS_animations) +- [Guide: Using CSS animations](/en-US/docs/Web/CSS/Guides/Animations/Using) - [CSS animations](/en-US/docs/Web/CSS/Guides/Animations) module - [CSS scroll-driven animations](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations) module diff --git a/files/en-us/web/css/reference/values/timeline-range-name/index.md b/files/en-us/web/css/reference/values/timeline-range-name/index.md index a5930072b0f65ca..265c64d84231b26 100644 --- a/files/en-us/web/css/reference/values/timeline-range-name/index.md +++ b/files/en-us/web/css/reference/values/timeline-range-name/index.md @@ -7,7 +7,7 @@ spec-urls: https://drafts.csswg.org/scroll-animations/#typedef-timeline-range-na sidebar: cssref --- -The **``** {{glossary("enumerated")}} data type is a CSS identifier representing one of the predefined named timeline ranges inside a [view progress timeline](/en-US/docs/Web/CSS/CSS_scroll-driven_animations/Timelines). +The **``** {{glossary("enumerated")}} data type is a CSS identifier representing one of the predefined named timeline ranges inside a [view progress timeline](/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines). The `` keyword values are used in the following longhand and shorthand properties: From e5a75db45d7d1694f11fa1eaa224ca61469f2cef Mon Sep 17 00:00:00 2001 From: wbamberg Date: Fri, 28 Nov 2025 20:15:56 -0800 Subject: [PATCH 13/21] Add a federated identity guide (#41779) * Draft a federated identity guide * Update files/en-us/web/security/authentication/federated_identity/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update files/en-us/web/security/authentication/federated_identity/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * back-channel logout example sentence * OP->IdP * Clearer language * ... * ... * Clarify authorization code injection * Reword client id preamble * Update CSRF description * Add a section on FedCM * Link to BCP * Mention PKCE downgrade attacks * Recommend client auth based on public-key crypto * Add sections on choosing idps and a summary * Update wording for client secret * clarify that PKCE is not used when the attacks work * Apply suggestions from code review Co-authored-by: Hamish Willee * Hint that client===RP * Review feedback --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Hamish Willee --- .../federated-identity-overview.svg | 3 + .../federated_identity/index.md | 302 ++++++++++++++++++ .../federated_identity/oidc-auth-flow.svg | 3 + 3 files changed, 308 insertions(+) create mode 100644 files/en-us/web/security/authentication/federated_identity/federated-identity-overview.svg create mode 100644 files/en-us/web/security/authentication/federated_identity/index.md create mode 100644 files/en-us/web/security/authentication/federated_identity/oidc-auth-flow.svg diff --git a/files/en-us/web/security/authentication/federated_identity/federated-identity-overview.svg b/files/en-us/web/security/authentication/federated_identity/federated-identity-overview.svg new file mode 100644 index 000000000000000..bff6027b6e51d7c --- /dev/null +++ b/files/en-us/web/security/authentication/federated_identity/federated-identity-overview.svg @@ -0,0 +1,3 @@ + + +
User
RP (website)
IdP
1. Sign in
2. Request
user sign-in
3. Request credentials
4. Supply credentials
5. Send token
\ No newline at end of file diff --git a/files/en-us/web/security/authentication/federated_identity/index.md b/files/en-us/web/security/authentication/federated_identity/index.md new file mode 100644 index 000000000000000..3fa55a47dda8a6c --- /dev/null +++ b/files/en-us/web/security/authentication/federated_identity/index.md @@ -0,0 +1,302 @@ +--- +title: Federated identity +slug: Web/Security/Authentication/Federated_identity +page-type: guide +sidebar: security +--- + +In a **federated identity** system, a website delegates authentication to a third party. + +- The third party, which is commonly called an {{glossary("identity provider", "Identity Provider (IdP)")}}, manages a user's credentials and can authenticate users. +- The website, which is commonly called a {{glossary("relying party", "Relying Party (RP)")}}, trusts the IdP to make assertions about a user's identity. + +When the user wants to sign into the website, the website redirects them to the IdP. The user authenticates to the IdP, and the IdP returns a token to the website indicating that the user authenticated successfully. The website checks that the token is valid, and if it is, signs the user in. + +![Overview of federated identity sign-in.](federated-identity-overview.svg) + +> [!NOTE] +> Federated identity is not really an authentication _method_: it's more like an _architecture_ within which various different authentication methods could be used. That is, an IdP could choose to authenticate users with one or more methods, such as traditional passwords, one-time passwords, biometrics, or passkeys. + +This model has some benefits for both users and websites: + +- Websites don't have to implement their own authentication, or securely handle user {{glossary("credential", "credentials")}}. +- A single IdP can authenticate users for many different websites. This means that the user doesn't have to use a different credential for each site: if credentials are passwords, this reduces the risk of password reuse or the user choosing weak, easy-to-remember passwords. +- If a user already has an account with an IdP that your website trusts to authenticate users, then it's much easier for users to sign up to your site, because they don't need to get new credentials specifically for your site. + +In this guide we'll explore how a website can work with an IdP to add federated sign-in for their users. We'll cover: + +- The main flows defined in the [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) protocol, which is the dominant standard for federated identity, and good practices to follow when implementing them. +- How browser restrictions on third-party cookies create problems for federated identity implementations. +- The [Federated Credential Management (FedCM) API](/en-US/docs/Web/API/FedCM_API), which makes the browser's role much more active, to simplify the role of the RP and avoid relying on third-party cookies. +- How a website can choose an IdP to work with, and how this choice can affect the process of implementing federated sign-in. + +## OpenID Connect + +The standard most commonly used for federated identity on the web is [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/), which is an authentication protocol built on top of the [OAuth 2.0 authorization framework](https://datatracker.ietf.org/doc/html/rfc6749). + +### Authentication flow + +In this section we'll start by walking through the main authentication flow defined in OIDC. There are many options within the OIDC authentication flow: in this walkthrough we'll present the recommended options, and we will talk later about alternatives. + +This flow is defined in the [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html) specification. + +As a prerequisite, the RP needs to be known to the IdP: + +- The IdP needs to have an identifier for the RP, which is called a client ID +- The RP must be able to authenticate itself to the IdP + +Authentication could use a shared secret called a client secret or some other mechanism such as TLS client authentication. + +> [!NOTE] +> The OpenID specifications use the term "OpenID Provider" (OP) to refer to what we call an IdP in this guide. + +![The OIDC authentication flow](oidc-auth-flow.svg) + +The first thing to note here is that the flow consists of two parts. + +- **Authentication request**: the RP makes a request to the IdP's _authorization endpoint_, asking the IdP to authenticate the user. The IdP authenticates the user and returns an _authorization code_ to the RP. The code expires after a short period of time (recommended to be no more than 10 minutes). +- **Token request**: the RP sends the authorization code to a separate endpoint in the IdP, called the _token endpoint_, and this endpoint responds with an object containing two tokens: + - An _access token_, which enables the user to access specific resources in the website (like an API key) + - An _ID token_, which identifies the user, and enables the RP to sign the user in. + +In the authentication request: + +1. The user asks to sign into the RP. + +2. The RP redirects the browser to the IdP's authorization endpoint, asking it to authenticate the user. The RP can provide various parameters along with the request, including: + - `client_id`: Identifies this RP to the IdP. + - `response_type`: Always `"code"` if we are using the two-part flow described here, which is the recommended option. + - `redirect_uri`: The URL in the RP, that the IdP should redirect to once it has attempted to authenticate the user. This is the URL to which the IdP will deliver the authorization code. + - `code_challenge`: A cryptographic {{glossary("hash")}} of a secret specific to this authorization request, which will be used by the token endpoint to ensure that the token request is really the counterpart of this authorization request. + - `scope`: A list of strings that specify which sets of user data the RP wishes to access. + +3. The IdP authenticates the user. The protocol does not specify a particular method for this: the IdP could use a password, a one-time password, a biometric, or any other appropriate method. + +4. If authentication is successful, the IdP generates the authorization code. It also stores the `code_challenge` value, and associates it with the authorization code. The IdP then redirects the browser to the RP's redirect URL, passing the authorization code as a parameter. + +In the token request: + +1. The RP makes a {{httpmethod("POST")}} request to the IdP's token endpoint. This request includes the following parameters: + - `client_id`: Identifies this RP to the IdP. + - `client_secret`: The secret used to authenticate the RP to the IdP: this could be any value previously agreed between the RP and the IdP. Instead of a shared secret, the RP and the IdP could use some alternative mechanism for client authentication, such as TLS client authentication. + - `grant_type`: This should be `"authorization_code"`. + - `code`: The authorization code. + - `code_verifier`: This is the original secret that was used to produce the `code_challenge` parameter in the authentication request. + +2. The IdP validates the request: + - It authenticates that the request is from the particular RP using the client secret or some other form of client authentication. + - It hashes the `code_verifier` parameter, and then checks that the result matches `code_challenge`. + +3. If the request is valid, the IdP responds with two tokens: + - An access token, which grants the user access to some resource in the RP. + - An ID token, which identifies the user. This is a cryptographically signed [JSON Web Token](https://www.jwt.io/). + +4. The RP validates the tokens: among other checks, it verifies the IdP's signature on the ID token. If validation succeeds, the RP signs the user in. + +### Security features + +In this section we will summarize the main security features of the OIDC authentication flow we've just described. For the full details, see [Best Current Practice for OAuth 2.0 Security](http://www.rfc-editor.org/rfc/rfc9700.html). + +#### Authorization code flow + +The two-step flow we have described is called the "authorization code flow". In an alternative flow, called the "implicit flow", only the first step exists, and the response to the authentication request already contains the access and ID tokens. This is unsafe, because the tokens are exposed to the RP's front end, which is regarded as much less secure than the back end. For example, in a successful [XSS](/en-US/docs/Web/Security/Attacks/XSS) attack, or if the user installs a malicious browser extension, then the attacker might be able to steal the user's tokens. + +For this reason, websites should always use the authorization code flow. Even if an attacker can steal the authorization code, they still need to convince the token endpoint to give them the tokens in exchange for the code. + +#### Client authentication + +In the flow we have described, the RP authenticates itself to the token endpoint when it makes the token request. This means that if an attacker does manage to steal the authorization code, it still has to successfully impersonate the RP to get the tokens from the IdP. + +The OAuth specification distinguishes between [_confidential_ and _public_ clients](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1). Confidential clients are essentially RPs that can keep a secret, and public clients are those that can't. + +The specification considers that clients running on the user's browser are public clients, for the same reason we've already encountered: it's too easy for an attacker to access secrets in a browser via attacks such as XSS. Clients running on a web _server_ are confidential clients. + +In OIDC, only confidential clients may use client authentication, because only confidential clients can be trusted to maintain the security of the client's credentials. + +The RP can authenticate itself to the IdP using a shared secret, but [it is better to use a method based on public-key cryptography](https://www.rfc-editor.org/rfc/rfc9700.html#name-client-authentication), such as {{glossary("TLS")}} client authentication. + +#### Proof Key for Code Exchange (PKCE) + +The `code_challenge` and `code_verifier` values that the RP provides in the authentication request and token request, respectively, are part of a mechanism called _Proof Key for Code Exchange_ (PKCE), specified in {{rfc("7636")}}. + +In the authentication request: + +- The RP generates a value that is hard to guess and is specific to this authentication request. This value is called the _code verifier_. +- The RP creates a {{glossary("hash", "cryptographic hash")}} of the code verifier, and uses it as the `code_challenge` parameter in the authentication request. +- The IdP stores the code challenge, and associates it with the authorization code that it returns to the RP. + +In the token request: + +- The RP passes the code verifier in the _code_verifier_ parameter. +- The IdP hashes the code verifier, and compares the result with the stored code challenge: if they do not match, then the token request is denied. + +PKCE defends against two attacks: [CSRF against the RP's redirect URL](#csrf_against_the_redirect_url), and [authorization code injection](#authorization_code_injection). + +##### CSRF against the redirect URL + +In a CSRF attack, the attacker tricks the user's browser into signing the user into the attacker's account. This can have various bad effects: for example, any private data the user uploads to the account is available to, and under control of, the attacker. + +If PKCE were not used, the CSRF attack works as follows: + +1. The attacker asks to sign into the RP. The RP makes an authentication request to the IdP and the attacker authenticates to the IdP. + +2. The IdP generates an authorization code for the attacker, and redirects the attacker's browser to the RP's redirect URL, with the authorization code as a URL parameter. + +3. The attacker intercepts this redirect, extracts the redirect URL including the authorization code, and terminates the flow. + +4. The attacker tricks the user into clicking the redirect URL. To the RP, this looks like a response from the IdP to an authentication request originating from the user. + +5. The RP makes a token request to the IdP, including the attacker's authorization code, which it took from the redirect URL. + +6. The IdP responds with the attacker's tokens. + +7. The RP signs the user into the attacker's account: now any information or instructions they provide are under the attacker's control. + +Essentially, the attack succeeds because the RP doesn't know that the request to the redirect URL is not a response to a request made on behalf of the user. + +When PKCE is used: + +- In step 1, the RP generates a code verifier for the attacker's request, and sends the hashed code verifier (the code challenge) to the IdP. +- In step 2, the IdP stores the code challenge alongside the attacker's authorization code. +- In step 5, the RP won't be able to find a code verifier for the user that matches the challenge the IdP stored, so the token request will fail. + +An alternative defense is the `state` parameter defined in OAuth 2.0. In this defense, the RP provides an unpredictable value as a parameter in the authentication request, and the IdP includes the same value in the response: the RP checks that they match. Because the attacker can't predict the value of `state`, they can't pass a matching value to the RP's redirect URL. + +##### Authorization code injection + +In an authorization code injection attack, the attacker steals an authorization code from the target user, and is able to inject it into the attacker's own sign-in flow. The result is that the attacker is signed into the user's account. + +It's generally accepted that authorization codes in OIDC are vulnerable, in part because they're exposed to the user's browser. For example, if the user installs a malicious browser extension, then it will be able to steal authorization codes. + +The main mitigation here is [client authentication](#client_authentication): because the RP authenticates itself to the IdP when it makes a token request, an attacker can't just make their own token request with the stolen code. However, with the authorization code injection attack, it's the real RP making the token request, so client authentication is successful. + +If PKCE were not used, the authorization code injection attack works as follows: + +1. The attacker is able to steal the user's authorization code. For example, the user has installed a malicious browser extension that can access the URLs that the browser visits. + +2. The user tries to sign in. The RP makes an authentication request, the user authenticates, and the IdP redirects the browser to the RP's redirect URL, with the authorization code as a URL parameter. + +3. At this point, the malicious browser extension retrieves the authorization code, sends it to the attacker, and terminates the user's authentication flow. + +4. The attacker receives the user's authorization code. + +5. The attacker starts its own OIDC authentication flow, but intercepts the IdP's authentication response, replacing the authorization code with the code it stole from the user. This is straightforward, because the authentication response is for the attacker, so it passes through the attacker's device. + +6. The RP then continues its authentication flow for the attacker by making the token request to the IdP, including the user's authorization code that the attacker has injected. + +7. The IdP responds with the user's tokens. + +8. The RP signs the attacker into the user's account. + +Note that using a `state` parameter doesn't help in this case, because the authentication request and response really do belong to the same flow - the attacker's. + +PKCE protects against this attack, because: + +- In step 2, the RP generates a code verifier and sent the hashed code challenge to the IdP, which stores the challenge alongside the user's code. +- In step 6, the RP's token request contains the _attacker's_ code verifier but the _user's_ code. The IdP looks up the code challenge for the user's code: it won't match the attacker's code verifier, and the token request will be denied. + +An alternative to PKCE, specified in OIDC, is the [`nonce`](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-nonce) value. The RP includes this as another parameter in the authentication request: the IdP stores it, and the token endpoint returns it to the RP along with the tokens. The RP then checks that the returned value is the same as the original value. + +##### Ensuring that PKCE is used + +To ensure that PKCE is used, the RP must confirm that its chosen IdP not only supports PKCE, but that it also _mandates_ the use of PKCE — refusing the token request if a valid code verifier is not included. + +Otherwise, an RP is vulnerable to a [PKCE downgrade attack](https://datatracker.ietf.org/doc/html/rfc9700#name-pkce-downgrade-attack), in which an attacker tricks the IdP into thinking that the RP does not wish to use PKCE in a token request. + +### Architectures for OIDC clients + +The [OAuth 2.0 for Browser-Based Applications](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps-25) specification describes how web application architecture can affect the security threats faced by OIDC clients (that is, relying parties), and makes some recommendations for web application architecture. + +In particular, it finds that: + +- The most secure pattern is one in which the website uses a web server to handle all OAuth/OIDC interactions and interactions with APIs that are protected by access tokens. In this pattern, the RP can be a confidential client, because it can keep client secrets in the server. It can also keep all tokens in the server, including access tokens. + +- The next most secure pattern is one in which the website uses a web server to handle all OAuth/OIDC interactions, but then returns the access token to the front end, and the front end then makes API requests directly. In this scenario the website can be a confidential client but malicious code running in the browser (for example, through an XSS attack) can potentially steal access tokens. However, the front end doesn't have to store access tokens long-term: it can retrieve them from the backend when it needs them. + +- The least secure pattern is one in which OAuth/OIDC interactions and interactions with APIs both take place in the front end. This, for example, would be the natural architecture for an application that executes entirely in the browser. In this architecture the RP can't be a confidential client, because it can't reliably keep a client secret. This means that it can't authenticate itself to the IdP. It also has to persistently store tokens, which increases the risk of malicious code stealing them. + +The specification also includes detailed recommendations for security practices to follow in each of these three scenarios. + +### OIDC sign-out + +Sign-out scenarios are more complex in a federated identity system than in a non-federated system, because: + +- The user might sign out of the RP either on the RP's site or on the IdP's site. +- The user might choose to sign out of the RP only, or to sign out globally: that is, to sign out of all RPs that they are signed into with this IdP. This is a common requirement when we use federated identity to build a {{glossary("single sign-on", "single sign-on (SSO)")}} system, in which an employee might use a single set of corporate credentials to sign into email, a bug tracker, and a discussion forum. + +Supporting these scenarios means implementing some communication mechanism between the RP and the IdP. For example: + +- If the user signs out at the IdP, then the RP should be notified, and sign the user out in the RP. +- If the user signs out at the RP, then the IdP should be notified, and be able to sign the user out of all RPs that they are currently signed into. + +The OpenID specifications define two general approaches to implementing this coordination, which they call "front channel logout" and "back channel logout". + +In [front channel logout](https://openid.net/specs/openid-connect-frontchannel-1_0.html), the browser is used to mediate the communication. In this approach, the sender's page embeds an {{htmlelement("iframe")}} whose content is loaded from the recipient. For example, if the user signs out at the IdP, the IdP may embed an `