Skip to content
This repository has been archived by the owner on Nov 16, 2021. It is now read-only.

Component styling rules for layout containment #8

Open
dvoytenko opened this issue Feb 28, 2020 · 2 comments
Open

Component styling rules for layout containment #8

dvoytenko opened this issue Feb 28, 2020 · 2 comments
Labels
question Further information is requested

Comments

@dvoytenko
Copy link
Contributor

Layout containment

We have two major layout containment styles:

  1. No layout containment: the element's layout fully depends on its content.
  2. Layout containment: the element's size is invariant. The content usually adopts to the container.

Here, we'll focus on the layout containing components.

Styling needs

  1. We need to allow a caller to set component styles using their preferred technology: anything from a classical className + stylesheet, to inline style attribute, to CSS-in-JS solutions such as styled-components.
  2. However, we need to ensure that the internal component style is "hard" to break.

An example of using a styled component

import {AmpCarousel} from '@ampproject/carousel';
import styled from 'styled-components';

const MyCarousel = styled(AmpCarousel)`
  background: yellow;
  color: blue;
  font-family: Roboto;

  position: fixed;
  bottom: 0;
  height: 200px;
  width: 200px;

  & > button[arrow-next] {
    border-color: red;
  }
`;

This will likely result in the following stylesheet and markup:

<style>
.MyCarousel123 {
  background: yellow;
  color: blue;
  font-family: Roboto;

  position: fixed;
  bottom: 0;
  height: 200px;
  width: 200px;
}

.MyCarousel123 > button[arrow-next] {
  border-color: red;
}
</style>

<div class="MyCarousel123">
  <!-- internal component markup -->
</div>

There some things here, both desirable and not:

  • There are usually very little risks associated with "theming" styles, such as colors, fonts, etc.
  • We have to allow layout/position styling, but we need to ensure they don't conflict with component's own styling. A layout containing component would normally need position: relative style. So if it were to placed naively on the component element's root, it'd come with the direct conflict with position:fixed defined by the user stylesheet.
  • Some selectors could be harmful. For instance, the & > button[arrow-next] above invites users to be as selective as possible, but creates backward compatibility problems.

Implementation approaches

1. Merging styles (likely not good)

Naively, the component could simply look like this:

export default function AmpCarousel(props) {
  const {style, children} = props;
  return (
    <div {...props}
         style={{
           ...style,
           position: 'relative',
           width: '100%',
           height: '100%',
           overflow: 'auto hidden',
           display: 'flex',
         }}>
      {React.Children.map(childen, child => (
        React.cloneElement(child, {style: {...child.style, flex: '100% 0 0'}})
      ))}
    </div>
  );
}

Notice, the same issues arise for both: the root element of the component and for each child (slide). We can overwrite the styles passed by the user. At best, the user styles are ignored; at worst we break the user styles, or they could even come into an unexpected conflict. Here, we change the user's position:fixed to position:relative and also changed height and width. There are also a lot of assumptions go into this: width/height: 100% relative to what? How can users change width and height here? Only with a parent container? This is not obvious.

2. Nesting.

This approach takes more nesting. It might have a minor performance impact, but it also brings the needed isolation.

export default function AmpCarousel(props) {
  return (
    <div {...props}>
      <div
        style={{
          position: 'relative',
          width: '100%',
          height: '100%',
          overflow: 'auto hidden',
          display: 'flex',
        }}
        >
        {React.Children.map(childen, child => (
          <div style={{flex: '100% 0 0'}}>{child}</div>
        ))}
      </div>
    </div>
  );
}

These inline styles are really annoying

Yeah. See #7.

@dvoytenko dvoytenko added the question Further information is requested label Feb 28, 2020
@dvoytenko
Copy link
Contributor Author

/cc @caroqliu @jridgewell

@dvoytenko
Copy link
Contributor Author

/cc @wassgha

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question Further information is requested
Projects
Development

No branches or pull requests

1 participant