Fixed layout trample pit caused by deep thinking

“This is the first day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021”

The story background

Scene 1: A few days ago, I saw a colleague dealing with a page bug. Roughly, there was an input component that needed to be placed on the top after clicking. He designed it to apply fixed layout after clicking, set top = 0, left = 0, but it seemed that the component was not stuck to the top layer. Where the component’s ancestor element sets the Transform property.

Scene 2: That night, ON a whim, I wrote a mask + popup prompt function. The mask and popup used fixed layout, and the mask realized the function of background blur. I thought I’d center the popover, but it didn’t. It stuck to the bottom of the screen.

knowledge

Fixed position: Elements are removed from the normal document flow. No space is reserved for elements, but they are positioned by specifying their position relative to the screen viewport. The position of the element does not change as the screen scrolls. When printing, the element will appear in a fixed position on each page. The fixed property creates a new cascading context. When the element ancestor’s transform, Perspective, or filter attribute is not None, the container changes its viewport to that ancestor. – derived from the position – CSS (cascading style sheets (CSS) | MDN (mozilla.org)”

As a CSS newbie, I did not know that fixed positioning is not necessarily relative to the screen viewport, but in some cases, relative to some ancestral elements, as mentioned in the MDN document above. At first I was wondering if the parent container has fixed location as well, ε=(´ο ‘*)).

As luck would have it, the colleague translated the ancestor element using transform, and I set a background blur for the popover’s parent component, the mask. Blur (4px) filter included backdrop backdrop (4px). , just touch the special case of fixed positioning, so there is no relative viewport positioning.

Bug recurrence and improvement

The core code is roughly as follows

const Modal = (/ *... * /) = > {
  // ...
  const styleModal: CSSProperties = {
    boxShadow: '0 2px 10px var(--shadow-color)'.minWidth: '200px'.maxWidth: '300px'.minHeight: '150px'.position: 'fixed'.top: '50%'.left: '50%'.zIndex: 101.padding: '10px'.transform: 'translate(-50%, -50%)'.color: 'var(--text-color)'.background: 'var(--bg-color)'.wordBreak: 'break-all'
  }
  const styleMask: CSSProperties = {
    width: '100vw'.height: '100vw'.top: 0.left: 0.position: 'fixed'.backdropFilter: 'blur(10px)'.zIndex: 100.background: '# 33333333'
  }
  // ...
  return (
    <div style={styleMask}>
      <div className=' ' style={styleModal}>
       <! -... -->
      </div>
    </div>)}export default Modal
Copy the code

I thought so

The result is this

I talked about that in the last video, but how do I get the popover that I want?

Scheme 1: Change the position of the popover element inside to sticky. Sticky will be positioned relative to the nearest scrollable ancestor. As long as overflow of the grandfather container is not specially set, it will be positioned relative to the root element to achieve the same effect as fixed.

As long as there is no special parent element, it will not be affected by the parent container. It is simple and direct. For multiple elements with fixed layout, z-index can be set to control the hierarchical relationship between each other.

Afterword.

On November 1, returned home is more than 10 points, wanted to send before 12 o ‘clock in the Denver nuggets in the first article, the results haven’t write dry near 12 o ‘clock, want to hurry to submit, but did not even find where to input the title, time has come to 0:00, since have the next day, that is better than write well, write something practical.

extension

How to make the effect of mask + popover not so monotonous?

Background backdrop backdrop backdrop backdrop backdrop backdrop backdrop backdrop backdrop backdrop backdrop backdrop Blur (10px) with a popover in front and box-shadow in the center (fixed position through left:50%; Center the top left corner of the popover, where the percentage is relative to the parent element, and set transform: Translate (-50%, -50%) to compensate, where the percentage is relative to itself. The user calls the wrapped function showToast to immediately display the mask and popover. The main function of the mask is to prevent the area outside the popover from being clicked.

Advanced effect: added an animation transition when showToast – popup floating. Here we abstract the mask and popover styles into two classes:.mask and.modal. The style code is shown below. One detail is the use of the calc() attribute when defining animation frames, which as its name suggests evaluates an expression that mixes percentages and pixels, allowing me to translate(-50%, calc(-50% + 30px)); Accurately control the start of the animation popover from the center to the bottom 30px position.

.mask {
  width: 100vw;
  height: 100vh;
  top: 0;
  left: 0;
  position: fixed;
  backdrop-filter: blur(10px);
  z-index: 100;
  background: # 33333333;
}
.modal {
  box-shadow: 0 2px 10px var(--shadow-color);
  min-width: 200px;
  max-width: 300px;
  min-height: 150px;
  position: sticky;
  top: 50%;
  left: 50%;
  z-index: 101;
  padding: 10px;
  color: var(--text-color);
  background: var(--bg-color);
  word-break: break-all;
  animation: float ease-out 600ms forwards;
}

@keyframes float {
  from {
    transform: translate(-50%.calc(-50% + 30px));
    opacity: 0;
  }
  to {
    transform: translate(-50%, -50%);
    opacity: 1; }}Copy the code

The resources

The position – CSS (cascading style sheets (CSS) | MDN (mozilla.org)