Skip to content

absolute child element percent length of left/top/right/bottom/width/height calcuated different compared with web #850

Description

@qcclcr

Report

Issues and Steps to Reproduce

I found in yoga when absolute child element has percent length, it calculate base on parent‘s contentEdge but not padding Edge(which should be, https://www.w3.org/TR/CSS2/box.html#padding-edge
https://www.w3.org/TR/CSS2/visuren.html#propdef-left)。

As CSS defines:

Left,Like 'top', but specifies how far a box's left margin edge is offset to the right of the left edge of the box's “containing block”. For relatively positioned boxes, the offset is with respect to the left edge of the box itself.

10.1 Definition of "containing block"
The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:

1、The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The 'direction' property of the initial containing block is the same as for the root element.
2、For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.
3、If the element has 'position: fixed', the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media.
4、**If the element has 'position: absolute'**, the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
    a、In the case that the ancestor is an inline element, the containing block is the bounding box 
          around the padding boxes of the first and the last inline boxes generated for that element. In 
          CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
    b、Otherwise, the containing block is formed by the **padding edge of the ancestor**.
    If there is no such ancestor, the containing block is the initial containing block.

Expected Behavior

height of child is expected to be 1000px * 50% = 500px; and in web it is 500px

Actual Behavior

but in yoga it's value is (1000px - 200px -200px) * 50% = 300px

Link to Code

First Demo, if child is absolute , it is wrong

<html>
<body>
  <div class="heightWidthPaddingVertical" style="position: relative; box-sizing:border-box; flex-direction:column; align-items:center; justify-content:center; width:750px; height:1000px; padding-top:200px;
  padding-bottom:200px; background-color:green;">
    <div class="heightWithPercent" style="position:absolute; box-sizing:border-box; width:750px; height:50%; background-color:red;"></div>
  </div>
</body>
</html>

Second Demo, if child is relative, it is right as web

<html>
<body>
  <div class="heightWidthPaddingVertical" style="position: relative; box-sizing:border-box; flex-direction:column; align-items:center; justify-content:center; width:750px; height:1000px; padding-top:200px;
  padding-bottom:200px; background-color:green;">
    <div class="heightWithPercent" style="position:relative; box-sizing:border-box; width:750px; height:50%; background-color:red;"></div>
  </div>
</body>
</html>

When applicable, use this fiddle to post a web repro.
@emilsjolander @woehrl01 @davidaurelio

Activity

  1. changed the title [-]absolute child element percent length of left/top/right/bottom/width/height calcuated wrong compared with web[/-] [+]absolute child element percent length of left/top/right/bottom/width/height calcuated different compared with web[/+] on Jan 10, 2019
  2. davidaurelio commented on Jan 28, 2019

    @davidaurelio
    Contributor

    Thanks for reporting. I will have to verify whether a fix is viable.

    Unfortunately, we have a vast amount of code at FB that depends on Yoga, and we might not be able to fix all bugs.

  3. self-assigned this
    on Jan 28, 2019
  4. Sharcoux commented on Mar 6, 2019

    @Sharcoux

    React-Native depends on Yoga, and React-Native-Web depends on React-Native. That's a lot of projects depending on Yoga. If Yoga doesn't follow the specs but only Facebook own interpretation of the specs, I think I would rather stop relying on it too much...

  5. wjlotus1992 commented on Jul 9, 2019

    @wjlotus1992

    I also have this problem and hope fix this bug as soon as possbile

  6. Sharcoux commented on Jul 9, 2019

    @Sharcoux

    Thanks for reporting. I will have to verify whether a fix is viable.

    Unfortunately, we have a vast amount of code at FB that depends on Yoga, and we might not be able to fix all bugs.

    That is really scary when you know that apparently, no one is able to keep contributing to Yoga nor react-native. I am trying to contribute for months to Yoga and React-Native, but I still couldn't, despite asking for help on both projects github pages, on the discord, I even tried to send a message to the last contributor via Facebook out of despair.

  7. Weey0001 commented on Jul 12, 2019

    @Weey0001

    hi, i have a child element that i want have 100% of the width of the windows without change the parent vue , how can i fix it ?

  8. woehrl01 commented on Jun 11, 2020

    @woehrl01
    Contributor

    Hi @qcclcr,

    I just pushed a fix for that bug. Let's see how this will be decided by Facebook's current maintainer.

  9. removed their assignment
    on Jun 19, 2020
  10. davidaurelio commented on Jun 19, 2020

    @davidaurelio
    Contributor

    @SidharthGuglani could you take a look, please? Thank you!

  11. goodgoodbigbig commented on Aug 24, 2020

    @goodgoodbigbig

    Hi @qcclcr,

    I just pushed a fix for that bug. Let's see how this will be decided by Facebook's current maintainer.

    I tried your solution. But it seem wrong in the following test case

    YGNodeRef root = YGNodeNew();
        YGNodeStyleSetWidth(root, 288);
        YGNodeStyleSetHeight(root, 288);
        YGNodeStyleSetFlexShrink(root, 1);
        YGNodeStyleSetAlignItems(root, YGAlign::YGAlignFlexStart);
        YGNodeStyleSetJustifyContent(root, YGJustify::YGJustifyFlexStart);
        // YGNodeStyleSetFlexDirection(root, YGFlexDirection::YGFlexDirectionRow);
        YGNodeStyleSetFlexDirection(root, YGFlexDirection::YGFlexDirectionColumn);
    
    
        YGNodeRef parent = YGNodeNew();
        YGNodeStyleSetHeight(parent, 24);
        YGNodeStyleSetFlexDirection(parent, YGFlexDirectionRow);
        YGNodeStyleSetAlignItems(parent, YGAlign::YGAlignFlexStart);
        YGNodeStyleSetAlignItems(parent, YGAlign::YGAlignFlexStart);
        YGNodeStyleSetFlexShrink(parent, 1);
        YGNodeStyleSetPositionType(parent, YGPositionTypeRelative);
    
        YGNodeInsertChild(root, parent, 0);
    
        YGNodeRef child1 = YGNodeNew();
        YGNodeStyleSetHeight(child1, 24);
        YGNodeStyleSetWidth(child1, 48);
        YGNodeStyleSetFlexShrink(child1, 1);
    
        YGNodeRef child2 = YGNodeNew();
        YGNodeStyleSetHeight(child2, 24);
        YGNodeStyleSetWidthPercent(child2, 100);
        YGNodeStyleSetFlexShrink(child2, 1);
        YGNodeStyleSetPositionPercent(child2, YGEdge::YGEdgeLeft, 50);
        YGNodeStyleSetPositionPercent(child2, YGEdge::YGEdgeBottom, -100);
        YGNodeStyleSetPositionType(child2, YGPositionTypeAbsolute);
        
        
        YGNodeInsertChild(parent, child1, 0);
        YGNodeInsertChild(parent, child2, 1);
    
        YGNodeCalculateLayout(root, 600, 600, YGDirectionLTR);
    
        YGNodePrint(root, YGPrintOptionsChildren);
    
        YGTraversePreOrder(root, [](YGNodeRef node) {
            float w = YGNodeLayoutGetWidth(node);
            float h = YGNodeLayoutGetHeight(node);
            float l = YGNodeLayoutGetLeft(node);
            float t = YGNodeLayoutGetTop(node);
            YGNodePrint(node, YGPrintOptionsLayout);
            std::cout << std::endl
                      << node << ": " << w << "x" << h 
                      << "   l:" << l << ", t: " << t 
                      << std::endl;
        });

    child2 is expected to 48x24 l:24, t: 24, but the result is 288x24 l:144, t: 288

  12. added a commit that references this issue on Dec 29, 2022
    1903212
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions