wg-bento
wg-bento copied to clipboard
Component styling rules for layout containment
Layout containment
We have two major layout containment styles:
- No layout containment: the element's layout fully depends on its content.
- 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
- We need to allow a caller to set component styles using their preferred technology: anything from a classical
className+ stylesheet, to inlinestyleattribute, to CSS-in-JS solutions such as styled-components. - 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: relativestyle. So if it were to placed naively on the component element's root, it'd come with the direct conflict withposition:fixeddefined 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 https://github.com/ampproject/wg-bento/issues/7.
I.e., what is being governed?
Hi @mnot; this is a good question. :)
From a more technical perspective, the AMP Project encompasses the contents of a GitHub organization which includes software, documentation, the project’s marketing website, and specifications, including those that define expectations for the AMP ecosystem, and design docs.
For a slightly more philosophical take, I generally point people toward's AMP's vision and mission.
@tobie we've talked a bit about this in the past; do you have anything else you'd add here?
There are a few extra assets worth considering once we move the project to a foundation:
- any trademarks, original designs, etc.
- the ampproject.org domain name.
- the associated CDN which hosts the JS files.
In his review @triblondon made the following comment which seems strongly related to this issue:
Define what AMP 'is', legally: Define the legal status of AMP. In the blog post accompanying this governance model, it says "Additionally, we’re exploring moving AMP to a foundation in the future". So currently, decisions made 'by AMP' are expressing the will of what entity? And when it does move to a foundation, of course it is equally important to document that structure.
is it an explicit goal for the specifications that the AMP project produces to be standardised by an external body?
With AMP joining the OpenJS Foundation I expect there will be more crispness over what "AMP" is, since it has to be clear what is actually moving (as discussed in the OpenJS Foundation onboarding checklist).