内容简介:The move to component-based development has enabled a large number of really incredible improvements to tools and the front-end ecosystem as a whole. Remember when we were building our apps as a set of screens and pages instead of thinking in components? T
The move to component-based development has enabled a large number of really incredible improvements to tools and the front-end ecosystem as a whole. Remember when we were building our apps as a set of screens and pages instead of thinking in components? The component model has changed this entirely - now, we think of pages as a composition of reusable components. As a result, we've also seen a huge increase in the number of open source UI components being built, published, and reused between applications. This modular approach to UI is vital to us at Visly since it's what enables our product to work with any app right away. In the pre-component era, we would have probably required you to build your whole app inside of Visly from scratch.
However, a lot of CSS layout patterns come from this pre-component era, and I want to discuss with you here how some of those patterns should be deprecated, as they break the modularity and composition assumptions of components.
Layout isolation
Before we jump into the properties and patterns we should be avoiding, I think it's worth exploring conceptually what we're trying to avoid. Essentially, we want to avoid any properties on the root element of a component that affect, or are affected by, elements outside of the bounds of that component.
I would discourage properties like margin
, because they act on elements outside of the component's scope; the same goes for properties like align-self
, as it will stretch the width or height of the component depending on the flex-direction
of its parent. In contrast, properties like padding
are fine, as they are confined to the scope of the component. Basically, if a property depends on, or impacts, other components outside of its scope, I would discourage using it.
Layout-isolated component- A component that is unaffected by the parent it is placed within, and does not itself affect the size and position of its siblings.
Something I think worth reiterating is that this only applies to the root element of a reusable component. So for example, as you can see in the code below, using align-self
does not make a component break layout isolation automatically, just if it is placed on the root element.
// Does NOT comform to layout isolation principals function MyComponent() { return ( <div style={{alignSelf: 'center'}}> <div /> </div> ) } // This component is layout isolated function MyComponent() { return ( <div> <div style={{alignSelf: 'center'}}/> </div> ) }
What properties make a component break layout isolation?
Any property which affects, or is affected by, elements outside a component scope are not layout isolated properties and should be avoided on the root layer of your component. I'll cover a couple of the most common properties (and why they pose a problem) below.
Align self
The reason align-self
is not layout-isolated is that it will apply vertical or horizontal alignment to the component depending on the direction of the container in which it's placed. It's especially bad when using stretch
, as setting that as the value means your component will end up stretching either vertically or horizontally depending on its container. Some components are built to be stretched in either direction, but this is not the case for the vast majority of components.
So how do you solve this? Should you stop using align-self
? Not at all! All you need to do to make your component reusable while still using align-self
is to allow the parent to pass in the alignment value.
// Don't do this. This component isn't very re-usable function MyComponent() { return <div style={{alignSelf: 'stretch'}}/> } // Do this. This component can be used from anywhere function MyComponent(props) { return <div style={{alignSelf: props.alignSelf}}/> }
Flex properties
Flex (flex-grow & flex-shrink) is a fun - though that may be my Stockholm syndrome speaking - and incredibly powerful property. However, as they say, with great power comes a great amount of bugs. Flex actually breaks layout isolation principles in two ways, which leads to countless bugs. Trust me - I was the go-to "flexbox guy" at Facebook for close to three years, and at least 25% of all problems people had were because they were re-using components with flex properties in contexts they weren't initially designed for.
So what does flex do? Flex describes how a component flexes in the main axis. What defines the main axis? The container. Which by definition makes flex break layout isolation. But even if that wasn't the case, there's a second aspect of flex properties that also make them affect components outside their scope. The amount a component flexes depends on its flex value in relation to the sum of all its siblings' flex values. So if you are expecting a component to flex into all the remaining space, that won't always be true, depending on the other siblings. Because of this, flex properties are doubly bad when it comes to making components reusable.
There is one important thing to note here. Flex shrink defaults to 1, which by this definition makes every single component with display: flex
break layout isolation. In my opinion, you should change this default because it creates a whole lot more problems than it solves. For this reason, components built in Visly all default to having flex-shrink
and flex-grow
set to 0.
Just like with align-self
, the solution is to move flex out of the component and into a prop that can be controlled by the wrapping component.
// Don't do this. This component isn't very re-usable function MyComponent() { return <div style={{flex: 1}}/> } // Do this. This component can be used from anywhere function MyComponent(props) { return <div style={{flex: props.flex}}/> }
Percentages
Percentage dimensions are like flex, but not quite as dangerous because the dimension they apply to does not depend on the parent component. However the size is by definition based on the percentage of the parent size. This means it can be quite easy to get into situations like the one below, where a button looks great in one context but terrible in another.
Percentage sizes being set on the button, by the button, are the problem here. And like all the other examples, it can be fixed by allowing the parent to set a percentage size on the button rather than having the button component itself control that.
// Don't do this. This component isn't very re-usable function MyComponent() { return <div style={{height: '100%'}}/> } // Do this. This component can be used from anywhere function MyComponent(props) { return <div style={{flex: props.height}}/> }
If you're building components in Visly, you'll notice that we allow setting the dimensions of a component to 100%
. While I don't personally believe that this something we should be using, because it's so common, we chose to support it in Visly. However, all components built in Visly have the ability to have their dimensions overridden by their parent, from either Visly or code.
Margins
Ever fixed a layout using negative margin? Ever wrapped a component in a div to add some extra margin? Both are quite common and serve a good lesson as to why components themselves should never include margin. The reason margin has this issue and padding doesn't is that margin applies to the space outside of the component, while padding applies to the space within. The amount of margin you want on a component depends on which siblings are next to it and the container where your component appears - highly context-specific knowledge that, if built to be reusable, your component should not know about.
While this can be solved, just like all the rest of these examples, by passing margin in as a prop from the parent, we have found a <Spacer/>
component to be far superior. Aside from the parent-dependency problems of margin, they have a discoverability problem. Is the spacing due to left margin on this component, or right margin on this other component? It's impossible to know without inspecting the DOM! <Spacer/>
components solve this and are also a lot easier to manipulate. Want that same spacing between two other elements? Just copy paste the spacer - much easier than fiddling with margins.
While not exactly the same as code, you can see a lot of these benefits in Visly. We don't support margins at all, instead relying on a spacer component. In an update coming soon, we will also be adding support for stack spacing, a concept where a container can configure the spacing between its children.
Tab index
Tab index doesn't change the visual layout of an element but it does impact the layout of an element for screen readers, or people who prefer navigating interfaces using their keyboard . Because it impacts the order of siblings, by definition it breaks layout isolation. Like the previous example, you'll want to move tab index out of the components' control and into its props so that it can be set by the parent.
Absolute positioning
This one is not as bad as the others, as it typically doesn't break anything; it may just make your component unusable in certain situations. For example, if you make a Notification
component, you may be inclined to add a position: absolute
rule on it, since notifications pop up on top of other content. However, later on, you may want to show the notifications within the context of a sidebar. In this case, you no longer want to position the notification with absolute coordinates.
Like all the previous examples, you can fix this by passing these styles in from above! You never know where your components may be used in the future. In this example we go further by declaring all the styles that can be set on the component as a subset of CSSProperties
.
import { CSSProperties } from 'react' type Style = Pick< CSSProperties, 'position' | 'left' | 'top' | 'right' | 'bottom' > interface Props { style: Style } // This component can be used from anywhere function MyComponent(props: Props) { return <div style={props.style}/> }
In conclusion
* { flex-shrink: 0; } <Spacer/>
The idea for this post came out of a twitter discussion with Max Stoiber who shares a lot of my thoughts on this - you should check out his thoughts on margin .
If you have any questions about Visly or comments on the article, please reach outover email or twitter . If you want to give Visly a try, please request access .
以上所述就是小编给大家介绍的《Layout-Isolated Components》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux命令行与shell脚本编程大全 第3版
[美]布鲁姆,布雷斯纳汉 / 门佳、武海峰 / 人民邮电出版社 / 2016-8-1 / CNY 109.00
这是一本关于Linux命令行与shell脚本编程的全方位教程,主要包括四大部分:Linux命令行,shell脚本编程基础,高级shell脚本编程,如何创建实用的shell脚本。本书针对Linux系统的最新特性进行了全面更新,不仅涵盖了详尽的动手教程和现实世界中的实用信息,还提供了与所学内容相关的参考信息和背景资料。通过本书的学习,你将轻松写出自己的shell脚本。一起来看看 《Linux命令行与shell脚本编程大全 第3版》 这本书的介绍吧!