forked from mirrors/gecko-dev
Bug 1769512 - Implement overflow-clip-margin: <length>. r=jwatt
Differential Revision: https://phabricator.services.mozilla.com/D146432
This commit is contained in:
parent
3d7fc1d193
commit
99908fb968
21 changed files with 194 additions and 90 deletions
|
|
@ -404,5 +404,5 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
|||
],
|
||||
["shadow", new Set(["box-shadow", "text-shadow"])],
|
||||
["paintServer", new Set(["fill", "stroke"])],
|
||||
["length", new Set(["font-size", "outline-offset", "outline-width"])],
|
||||
["length", new Set(["font-size", "outline-offset", "outline-width", "overflow-clip-box"])],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3114,6 +3114,7 @@ exports.CSS_PROPERTIES = {
|
|||
"margin-right",
|
||||
"margin-bottom",
|
||||
"margin-left",
|
||||
"overflow-clip-margin",
|
||||
"scroll-margin-top",
|
||||
"scroll-margin-right",
|
||||
"scroll-margin-bottom",
|
||||
|
|
@ -9063,6 +9064,20 @@ exports.CSS_PROPERTIES = {
|
|||
"visible"
|
||||
]
|
||||
},
|
||||
"overflow-clip-margin": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"overflow-clip-margin"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"inherit",
|
||||
"initial",
|
||||
"revert",
|
||||
"revert-layer",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"overflow-inline": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
|
|
|
|||
|
|
@ -11,6 +11,26 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */
|
||||
void OverflowAreas::ApplyOverflowClippingOnRect(nsRect& aOverflowRect,
|
||||
const nsRect& aBounds,
|
||||
PhysicalAxes aClipAxes,
|
||||
const nsSize& aOverflowMargin) {
|
||||
auto inflatedBounds = aBounds;
|
||||
inflatedBounds.Inflate(aOverflowMargin);
|
||||
|
||||
auto clip = aOverflowRect;
|
||||
if (aClipAxes & PhysicalAxes::Vertical) {
|
||||
clip.y = inflatedBounds.y;
|
||||
clip.height = inflatedBounds.height;
|
||||
}
|
||||
if (aClipAxes & PhysicalAxes::Horizontal) {
|
||||
clip.x = inflatedBounds.x;
|
||||
clip.width = inflatedBounds.width;
|
||||
}
|
||||
aOverflowRect = aOverflowRect.Intersect(clip);
|
||||
}
|
||||
|
||||
void OverflowAreas::UnionWith(const OverflowAreas& aOther) {
|
||||
InkOverflow().UnionRect(InkOverflow(), aOther.InkOverflow());
|
||||
ScrollableOverflow().UnionRect(ScrollableOverflow(),
|
||||
|
|
|
|||
|
|
@ -79,6 +79,23 @@ struct OverflowAreas {
|
|||
// Mutates |this| by setting both overflow areas to |aRect|.
|
||||
void SetAllTo(const nsRect& aRect);
|
||||
|
||||
// Applies overflow clipping (for e.g. overflow: clip) as needed to both our
|
||||
// overflow rects.
|
||||
void ApplyClipping(const nsRect& aBounds, PhysicalAxes aClipAxes,
|
||||
const nsSize& aOverflowMargin) {
|
||||
ApplyOverflowClippingOnRect(InkOverflow(), aBounds, aClipAxes,
|
||||
aOverflowMargin);
|
||||
ApplyOverflowClippingOnRect(ScrollableOverflow(), aBounds, aClipAxes,
|
||||
aOverflowMargin);
|
||||
}
|
||||
|
||||
// Applies the overflow clipping to a given overflow rect, given the frame
|
||||
// bounds, and the physical axes on which to apply the overflow clip.
|
||||
static void ApplyOverflowClippingOnRect(nsRect& aOverflowRect,
|
||||
const nsRect& aBounds,
|
||||
PhysicalAxes aClipAxes,
|
||||
const nsSize& aOverflowMargin);
|
||||
|
||||
private:
|
||||
nsRect mInk;
|
||||
nsRect mScrollable;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ enum LogicalCorner {
|
|||
// Physical axis constants.
|
||||
enum PhysicalAxis { eAxisVertical = 0x0, eAxisHorizontal = 0x1 };
|
||||
|
||||
// Represents zero or more physical axes.
|
||||
enum class PhysicalAxes : uint8_t {
|
||||
None = 0x0,
|
||||
Horizontal = 0x1,
|
||||
Vertical = 0x2,
|
||||
Both = Horizontal | Vertical,
|
||||
};
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PhysicalAxes)
|
||||
|
||||
inline LogicalAxis GetOrthogonalAxis(LogicalAxis aAxis) {
|
||||
return aAxis == eLogicalAxisBlock ? eLogicalAxisInline : eLogicalAxisBlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2139,35 +2139,46 @@ void nsBlockFrame::ComputeOverflowAreas(OverflowAreas& aOverflowAreas,
|
|||
const nsStyleDisplay* aDisplay) const {
|
||||
// XXX_perf: This can be done incrementally. It is currently one of
|
||||
// the things that makes incremental reflow O(N^2).
|
||||
if (ShouldApplyOverflowClipping(aDisplay) != PhysicalAxes::Both) {
|
||||
for (const auto& line : Lines()) {
|
||||
if (aDisplay->IsContainLayout()) {
|
||||
// If we have layout containment, we should only consider our child's
|
||||
// ink overflow, leaving the scrollable regions of the parent
|
||||
// unaffected.
|
||||
// Note: scrollable overflow is a subset of ink overflow,
|
||||
// so this has the same affect as unioning the child's visual and
|
||||
// scrollable overflow with its parent's ink overflow.
|
||||
nsRect childVisualRect = line.InkOverflowRect();
|
||||
OverflowAreas childVisualArea =
|
||||
OverflowAreas(childVisualRect, nsRect());
|
||||
aOverflowAreas.UnionWith(childVisualArea);
|
||||
} else {
|
||||
aOverflowAreas.UnionWith(line.GetOverflowAreas());
|
||||
}
|
||||
}
|
||||
auto overflowClipAxes = ShouldApplyOverflowClipping(aDisplay);
|
||||
auto overflowClipMargin = OverflowClipMargin(overflowClipAxes);
|
||||
if (overflowClipAxes == PhysicalAxes::Both &&
|
||||
overflowClipMargin == nsSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Factor an outside ::marker in; normally the ::marker will be factored
|
||||
// into the line-box's overflow areas. However, if the line is a block
|
||||
// line then it won't; if there are no lines, it won't. So just
|
||||
// factor it in anyway (it can't hurt if it was already done).
|
||||
// XXXldb Can we just fix GetOverflowArea instead?
|
||||
if (nsIFrame* outsideMarker = GetOutsideMarker()) {
|
||||
aOverflowAreas.UnionAllWith(outsideMarker->GetRect());
|
||||
}
|
||||
// We rely here on our caller having called SetOverflowAreasToDesiredBounds().
|
||||
nsRect frameBounds = aOverflowAreas.ScrollableOverflow();
|
||||
|
||||
ConsiderBlockEndEdgeOfChildren(aOverflowAreas, aBEndEdgeOfChildren,
|
||||
aDisplay);
|
||||
for (const auto& line : Lines()) {
|
||||
if (aDisplay->IsContainLayout()) {
|
||||
// If we have layout containment, we should only consider our child's
|
||||
// ink overflow, leaving the scrollable regions of the parent
|
||||
// unaffected.
|
||||
// Note: scrollable overflow is a subset of ink overflow,
|
||||
// so this has the same affect as unioning the child's visual and
|
||||
// scrollable overflow with its parent's ink overflow.
|
||||
nsRect childVisualRect = line.InkOverflowRect();
|
||||
OverflowAreas childVisualArea = OverflowAreas(childVisualRect, nsRect());
|
||||
aOverflowAreas.UnionWith(childVisualArea);
|
||||
} else {
|
||||
aOverflowAreas.UnionWith(line.GetOverflowAreas());
|
||||
}
|
||||
}
|
||||
|
||||
// Factor an outside ::marker in; normally the ::marker will be factored
|
||||
// into the line-box's overflow areas. However, if the line is a block
|
||||
// line then it won't; if there are no lines, it won't. So just
|
||||
// factor it in anyway (it can't hurt if it was already done).
|
||||
// XXXldb Can we just fix GetOverflowArea instead?
|
||||
if (nsIFrame* outsideMarker = GetOutsideMarker()) {
|
||||
aOverflowAreas.UnionAllWith(outsideMarker->GetRect());
|
||||
}
|
||||
|
||||
ConsiderBlockEndEdgeOfChildren(aOverflowAreas, aBEndEdgeOfChildren, aDisplay);
|
||||
|
||||
if (overflowClipAxes != PhysicalAxes::None) {
|
||||
aOverflowAreas.ApplyClipping(frameBounds, overflowClipAxes,
|
||||
overflowClipMargin);
|
||||
}
|
||||
|
||||
#ifdef NOISY_OVERFLOW_AREAS
|
||||
|
|
|
|||
|
|
@ -2699,18 +2699,24 @@ static void ApplyOverflowClipping(
|
|||
bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
|
||||
: disp->mOverflowClipBoxBlock) ==
|
||||
StyleOverflowClipBox::ContentBox;
|
||||
nsMargin bp = aFrame->GetUsedPadding();
|
||||
|
||||
nsMargin boxMargin = -aFrame->GetUsedPadding();
|
||||
if (!cbH) {
|
||||
bp.left = bp.right = nscoord(0);
|
||||
boxMargin.left = boxMargin.right = nscoord(0);
|
||||
}
|
||||
if (!cbV) {
|
||||
bp.top = bp.bottom = nscoord(0);
|
||||
boxMargin.top = boxMargin.bottom = nscoord(0);
|
||||
}
|
||||
|
||||
bp += aFrame->GetUsedBorder();
|
||||
bp.ApplySkipSides(aFrame->GetSkipSides());
|
||||
auto clipMargin = aFrame->OverflowClipMargin(aClipAxes);
|
||||
|
||||
boxMargin -= aFrame->GetUsedBorder();
|
||||
boxMargin += nsMargin(clipMargin.height, clipMargin.width, clipMargin.height,
|
||||
clipMargin.width);
|
||||
boxMargin.ApplySkipSides(aFrame->GetSkipSides());
|
||||
|
||||
nsRect rect(nsPoint(0, 0), aFrame->GetSize());
|
||||
rect.Deflate(bp);
|
||||
rect.Inflate(boxMargin);
|
||||
if (MOZ_UNLIKELY(!(aClipAxes & nsIFrame::PhysicalAxes::Horizontal))) {
|
||||
// NOTE(mats) We shouldn't be clipping at all in this dimension really,
|
||||
// but clipping in just one axis isn't supported by our GFX APIs so we
|
||||
|
|
@ -2726,11 +2732,30 @@ static void ApplyOverflowClipping(
|
|||
rect.height = o.height;
|
||||
}
|
||||
clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
|
||||
haveRadii = aFrame->GetBoxBorderRadii(radii, -bp);
|
||||
haveRadii = aFrame->GetBoxBorderRadii(radii, boxMargin);
|
||||
aClipState.ClipContainingBlockDescendantsExtra(clipRect,
|
||||
haveRadii ? radii : nullptr);
|
||||
}
|
||||
|
||||
nsSize nsIFrame::OverflowClipMargin(PhysicalAxes aClipAxes) const {
|
||||
nsSize result;
|
||||
if (aClipAxes == PhysicalAxes::None) {
|
||||
return result;
|
||||
}
|
||||
const auto& margin = StyleMargin()->mOverflowClipMargin;
|
||||
if (margin.IsZero()) {
|
||||
return result;
|
||||
}
|
||||
nscoord marginAu = margin.ToAppUnits();
|
||||
if (aClipAxes & PhysicalAxes::Horizontal) {
|
||||
result.width = marginAu;
|
||||
}
|
||||
if (aClipAxes & PhysicalAxes::Vertical) {
|
||||
result.height = marginAu;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void PaintDebugBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
|
||||
const nsRect& aDirtyRect, nsPoint aPt) {
|
||||
|
|
@ -9548,14 +9573,19 @@ static nsRect ComputeOutlineInnerRect(
|
|||
}
|
||||
const nsStyleDisplay* disp = aFrame->StyleDisplay();
|
||||
LayoutFrameType fType = aFrame->Type();
|
||||
auto overflowClipAxes = aFrame->ShouldApplyOverflowClipping(disp);
|
||||
if (overflowClipAxes == nsIFrame::PhysicalAxes::Both ||
|
||||
fType == LayoutFrameType::Scroll ||
|
||||
if (fType == LayoutFrameType::Scroll ||
|
||||
fType == LayoutFrameType::ListControl ||
|
||||
fType == LayoutFrameType::SVGOuterSVG) {
|
||||
return u;
|
||||
}
|
||||
|
||||
auto overflowClipAxes = aFrame->ShouldApplyOverflowClipping(disp);
|
||||
auto overflowClipMargin = aFrame->OverflowClipMargin(overflowClipAxes);
|
||||
if (overflowClipAxes == nsIFrame::PhysicalAxes::Both &&
|
||||
overflowClipMargin == nsSize()) {
|
||||
return u;
|
||||
}
|
||||
|
||||
const nsStyleEffects* effects = aFrame->StyleEffects();
|
||||
Maybe<nsRect> clipPropClipRect =
|
||||
aFrame->GetClipPropClipRect(disp, effects, bounds.Size());
|
||||
|
|
@ -9619,15 +9649,10 @@ static nsRect ComputeOutlineInnerRect(
|
|||
}
|
||||
}
|
||||
|
||||
if (overflowClipAxes & nsIFrame::PhysicalAxes::Vertical) {
|
||||
u.y = bounds.y;
|
||||
u.height = bounds.height;
|
||||
if (overflowClipAxes != nsIFrame::PhysicalAxes::None) {
|
||||
OverflowAreas::ApplyOverflowClippingOnRect(u, bounds, overflowClipAxes,
|
||||
overflowClipMargin);
|
||||
}
|
||||
if (overflowClipAxes & nsIFrame::PhysicalAxes::Horizontal) {
|
||||
u.x = bounds.x;
|
||||
u.width = bounds.width;
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
|
|
@ -9811,27 +9836,6 @@ bool nsIFrame::FinishAndStoreOverflow(OverflowAreas& aOverflowAreas,
|
|||
"Computed overflow area must contain frame bounds");
|
||||
}
|
||||
|
||||
// If we clip our children, clear accumulated overflow area in the affected
|
||||
// dimension(s). The children are actually clipped to the padding-box, but
|
||||
// since the overflow area should include the entire border-box, just set it
|
||||
// to the border-box size here.
|
||||
if (overflowClipAxes != PhysicalAxes::None) {
|
||||
nsRect& ink = aOverflowAreas.InkOverflow();
|
||||
nsRect& scrollable = aOverflowAreas.ScrollableOverflow();
|
||||
if (overflowClipAxes & PhysicalAxes::Vertical) {
|
||||
ink.y = bounds.y;
|
||||
scrollable.y = bounds.y;
|
||||
ink.height = bounds.height;
|
||||
scrollable.height = bounds.height;
|
||||
}
|
||||
if (overflowClipAxes & PhysicalAxes::Horizontal) {
|
||||
ink.x = bounds.x;
|
||||
scrollable.x = bounds.x;
|
||||
ink.width = bounds.width;
|
||||
scrollable.width = bounds.width;
|
||||
}
|
||||
}
|
||||
|
||||
// Overflow area must always include the frame's top-left and bottom-right,
|
||||
// even if the frame rect is empty (so we can scroll to those positions).
|
||||
// Pending a real fix for bug 426879, don't do this for inline frames
|
||||
|
|
@ -9846,6 +9850,15 @@ bool nsIFrame::FinishAndStoreOverflow(OverflowAreas& aOverflowAreas,
|
|||
}
|
||||
}
|
||||
|
||||
// If we clip our children, clear accumulated overflow area in the affected
|
||||
// dimension(s). The children are actually clipped to the padding-box, but
|
||||
// since the overflow area should include the entire border-box, just set it
|
||||
// to the border-box size here.
|
||||
if (overflowClipAxes != PhysicalAxes::None) {
|
||||
aOverflowAreas.ApplyClipping(bounds, overflowClipAxes,
|
||||
OverflowClipMargin(overflowClipAxes));
|
||||
}
|
||||
|
||||
// Note that StyleOverflow::Clip doesn't clip the frame
|
||||
// background, so we add theme background overflow here so it's not clipped.
|
||||
if (!::IsXULBoxWrapped(this) && IsThemed(disp)) {
|
||||
|
|
|
|||
|
|
@ -2935,17 +2935,11 @@ class nsIFrame : public nsQueryFrame {
|
|||
*/
|
||||
virtual void UnionChildOverflow(mozilla::OverflowAreas& aOverflowAreas);
|
||||
|
||||
// Represents zero or more physical axes.
|
||||
enum class PhysicalAxes : uint8_t {
|
||||
None = 0x0,
|
||||
Horizontal = 0x1,
|
||||
Vertical = 0x2,
|
||||
Both = Horizontal | Vertical,
|
||||
};
|
||||
// Returns the applicable overflow-clip-margin values.
|
||||
using PhysicalAxes = mozilla::PhysicalAxes;
|
||||
|
||||
/**
|
||||
* Returns true if this frame should apply overflow clipping.
|
||||
*/
|
||||
nsSize OverflowClipMargin(PhysicalAxes aClipAxes) const;
|
||||
// Returns the axes on which this frame should apply overflow clipping.
|
||||
PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
|
||||
|
||||
/**
|
||||
|
|
@ -5555,7 +5549,6 @@ class nsIFrame : public nsQueryFrame {
|
|||
#endif
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::PhysicalAxes)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::ReflowChildFlags)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -299,12 +299,15 @@ static StyleRect<T> StyleRectWithAllSides(const T& aSide) {
|
|||
nsStyleMargin::nsStyleMargin(const Document& aDocument)
|
||||
: mMargin(StyleRectWithAllSides(
|
||||
LengthPercentageOrAuto::LengthPercentage(LengthPercentage::Zero()))),
|
||||
mScrollMargin(StyleRectWithAllSides(StyleLength{0.})) {
|
||||
mScrollMargin(StyleRectWithAllSides(StyleLength{0.})),
|
||||
mOverflowClipMargin(StyleLength::Zero()) {
|
||||
MOZ_COUNT_CTOR(nsStyleMargin);
|
||||
}
|
||||
|
||||
nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
|
||||
: mMargin(aSrc.mMargin), mScrollMargin(aSrc.mScrollMargin) {
|
||||
: mMargin(aSrc.mMargin),
|
||||
mScrollMargin(aSrc.mScrollMargin),
|
||||
mOverflowClipMargin(aSrc.mOverflowClipMargin) {
|
||||
MOZ_COUNT_CTOR(nsStyleMargin);
|
||||
}
|
||||
|
||||
|
|
@ -324,6 +327,10 @@ nsChangeHint nsStyleMargin::CalcDifference(
|
|||
hint |= nsChangeHint_NeutralChange;
|
||||
}
|
||||
|
||||
if (mOverflowClipMargin != aNewData.mOverflowClipMargin) {
|
||||
hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -426,6 +426,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin {
|
|||
|
||||
mozilla::StyleRect<mozilla::LengthPercentageOrAuto> mMargin;
|
||||
mozilla::StyleRect<mozilla::StyleLength> mScrollMargin;
|
||||
// TODO: Add support for overflow-clip-margin: <visual-box> and maybe
|
||||
// per-axis/side clipping, see https://github.com/w3c/csswg-drafts/issues/7245
|
||||
mozilla::StyleLength mOverflowClipMargin;
|
||||
};
|
||||
|
||||
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding {
|
||||
|
|
|
|||
|
|
@ -6887,6 +6887,14 @@ var gCSSProperties = {
|
|||
other_values: ["auto", "scroll", "hidden", "clip"],
|
||||
invalid_values: [],
|
||||
},
|
||||
"overflow-clip-margin": {
|
||||
domProp: "overflowClipMargin",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: ["0px"],
|
||||
other_values: ["1px", "2em", "calc(10px + 1vh)"],
|
||||
invalid_values: ["-10px"],
|
||||
},
|
||||
padding: {
|
||||
domProp: "padding",
|
||||
inherited: false,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,16 @@
|
|||
)}
|
||||
% endfor
|
||||
|
||||
${helpers.predefined_type(
|
||||
"overflow-clip-margin",
|
||||
"Length",
|
||||
"computed::Length::zero()",
|
||||
parse_method="parse_non_negative",
|
||||
engines="gecko",
|
||||
spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-clip-margin",
|
||||
animation_value_type="ComputedValue",
|
||||
)}
|
||||
|
||||
% for side in ALL_SIDES:
|
||||
${helpers.predefined_type(
|
||||
"scroll-margin-%s" % side[0],
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
[overflow-clip-margin-001.html]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[overflow-clip-margin-002.html]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[overflow-clip-margin-004.html]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[overflow-clip-margin-005.html]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[overflow-clip-margin-invalidation.html]
|
||||
expected: FAIL
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
overflow: auto;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
/* Avoids some fuzz on scrollbar corners */
|
||||
scrollbar-color: blue blue;
|
||||
}
|
||||
.child {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
overflow: auto;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
/* Avoids some fuzz on scrollbar corners */
|
||||
scrollbar-color: blue blue;
|
||||
}
|
||||
.parent {
|
||||
width: 100px;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
overflow: auto;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
/* Avoids some fuzz on scrollbar corners */
|
||||
scrollbar-color: blue blue;
|
||||
}
|
||||
.child {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
overflow: auto;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
/* Avoids some fuzz on scrollbar corners */
|
||||
scrollbar-color: blue blue;
|
||||
}
|
||||
.parent {
|
||||
width: 100px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue