def expand_background(tokens, name, base_url):
    """Expand the ``background`` shorthand property.

    See https://drafts.csswg.org/css-backgrounds-3/#the-background

    """
    expanded_names = (
        'background-color', 'background-image', 'background-repeat',
        'background-attachment', 'background-position', 'background-size',
        'background-clip', 'background-origin')
    keyword = get_single_keyword(tokens)
    if keyword in ('initial', 'inherit'):
        for name in expanded_names:
            yield name, keyword
        return

    expander = functools.partial(
        expand_background, name=name, base_url=base_url)
    if result := _find_var(tokens, expander, expanded_names):
        yield from result.items()
        return

    def parse_layer(tokens, final_layer=False):
        results = {}

        def add(name, value):
            if value is None:
                return False
            name = f'background-{name}'
            if name in results:
                raise InvalidValues
            results[name] = value
            return True

        # Make `tokens` a stack
        tokens = tokens[::-1]
        while tokens:
            if add('repeat',
                   background_repeat.single_value(tokens[-2:][::-1])):
                del tokens[-2:]
                continue
            token = tokens[-1:]
            if final_layer and add('color', other_colors(token)):
                tokens.pop()
                continue
            if add('image', background_image.single_value(token, base_url)):
                tokens.pop()
                continue
            if add('repeat', background_repeat.single_value(token)):
                tokens.pop()
                continue
            if add('attachment', background_attachment.single_value(token)):
                tokens.pop()
                continue
            for n in (4, 3, 2, 1)[-len(tokens):]:
                n_tokens = tokens[-n:][::-1]
                position = background_position.single_value(n_tokens)
                if position is not None:
                    assert add('position', position)
                    del tokens[-n:]
                    if (tokens and tokens[-1].type == 'literal' and
                            tokens[-1].value == '/'):
                        for n in (3, 2)[-len(tokens):]:
                            # n includes the '/' delimiter.
                            n_tokens = tokens[-n:-1][::-1]
                            size = background_size.single_value(n_tokens)
                            if size is not None:
                                assert add('size', size)
                                del tokens[-n:]
                    break
            if position is not None:
                continue
            if add('origin', box.single_value(token)):
                tokens.pop()
                next_token = tokens[-1:]
                if add('clip', box.single_value(next_token)):
                    tokens.pop()
                else:
                    # The same keyword sets both
                    add('clip', box.single_value(token))
                continue
            raise InvalidValues

        color = results.pop(
            'background-color', INITIAL_VALUES['background_color'])
        for name in expanded_names:
            if name not in results and name != 'background-color':
                results[name] = INITIAL_VALUES[name.replace('-', '_')][0]
        return color, results

    layers = reversed(split_on_comma(tokens))
    color, last_layer = parse_layer(next(layers), final_layer=True)
    results = {key: [value] for key, value in last_layer.items()}
    for tokens in layers:
        _, layer = parse_layer(tokens)
        for name, value in layer.items():
            results[name].append(value)
    for name, values in results.items():
        yield name, values[::-1]  # "Un-reverse"
    yield 'background-color', color
Expand the ``background`` shorthand property.

See https://drafts.csswg.org/css-backgrounds-3/#the-background
weasyprint/css/validation/expanders.py