Components
Use oo-component to group recurring styling.
Loop semantic offers separation of concerns to differentiate components from other styling and to facilitate readibility. The HTML becomes easier to understand and to maintain while lightening the class attribute which can be too often overcrowded (A class with a component name along with a list of modifiers + a bunch of unrelated utilities).
By default, Loop components are used without the data attribute to remove verbosity and to get a shorter name for speed purposes oo-componentName
. You may turn on the option dataAttr
to be a fully-valid HTML attribute.
@include ooCreate((
dataAttr: false, // default oo-componentName
));
<!-- Column component -->
<div oo-row="align-center gutter-less" class="font-small text-center">
<div oo-col="span12 span3@sm"></div>
<div oo-col="span3@sm"></div>
<div oo-col="span3@sm"></div>
</div>
Loop components
- Column
oo-row
oo-col
- Template
oo-template
oo-area
- Button
oo-button
- Form
oo-input
oo-select
oo-radio
oo-checkbox
oo-toggle
Custom components
- Sample of situation
- Create component from Config
- Create component from Mixin
- Turn utility-first component into oo-component
# Custom components
Loop gives you the possibilty to create your own Loop syntax component. That offers you an alternative to regular css in the case of making a recurring style along with numerous modifiers.
Example of a situation
I created a reusable component for all the diverse messages of my project. I named it .notification
and namespaced each modifiers with it. I'm happy as it is extremely understandable.
<!-- Notification component -->
<div class="notification notification-success notification-large notification-centered">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component
</div>
You've created a success notification component.
It's a bit redundant. So I refactored the modifiers' logic by using keywords such as is
which I am using for utilities as well. I'm very happy as it is still extremely understandable with less writing.
<!-- Notification component with shorter modifier -->
<div class="notification is-success is-large is-centered">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component.
</div>
In the case where I'm adding utilities, the class attribute gets crowded, making it harder to know what's going on at a glance. I sometimes get confused between the modifiers and the utilities.
<!-- Notification component along with utilities -->
<div class="notification is-success is-large is-centered has-font-italic is-float-left is-hidden-print">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component.
</div>
I refactored my component again using Loop syntax. I'm extremely happy with the separation of concerns as I know what does what as well as avoiding redundant text.
<!-- Loop Notification component with Loop utilities -->
<div oo-notification="success large centered" class="font-italic float-left hidden@print">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component.
</div>
# Create from config
Pass css properties to props and to the variants name as a map value.
$ooLoop: ooAdd('components', (
'notification': (
props: (
padding: 1rem,
border-left-width: 5px,
border-left-style: solid,
box-shadow: 4px 4px 8px rgba(0, 0, 0, .15),
),
variants: (
'success': (
color: #015a31,
border-color: #83cca9,
background-color: #c8f7e1,
)
'danger': (
color: #5a0101,
border-color: #ca7878,
background-color: #f7c8c8,
),
'large': (
padding: 1.75rem 2rem,
font-size: 1.5rem,
),
'centered': (
text-align: center,
border-left: 0,
border-top-width: 5px,
border-top-style: solid,
)
)
),
));
<div oo-notification="danger centered">
<strong>Hey, well done!</strong><br>You've created a <i>danger</i> notification component.
</div>
You've created a danger notification component.
Target children elements
Use >
as a property name within the list of CSS properties to target nested elements. Then, define a map of CSS selector with CSS properties.
$ooLoop: ooAdd('components', (
'notification': (
props: (
padding: 1rem,
border-left-width: 5px,
border-left-style: solid,
box-shadow: 4px 4px 8px rgba(0, 0, 0, .15),
'>': (
'strong': (
text-transform: uppercase,
font-size: 1.1em,
)
)
),
variants: (...)
),
));
<div oo-notification="danger centered">
<strong>Hey, well done!</strong><br>You've created a <i>danger</i> notification component.
</div>
You've created a danger notification component.
Target pseudo-elements
Use before
and after
as property name and assign a map of CSS properties as value.
$ooLoop: ooAdd('components', (
'notification': (
props: (
...,
'::before' : (
margin-left: 10px,
float: right,
width: 22px,
height: 22px,
color: #fff,
text-align: center,
border-radius: 50%,
),
),
variants: (
'success': (
color: #015a31,
border-color: #83cca9,
background-color: #c8f7e1,
'::before': (
content: '\2713',
background-color: #4ea97d,
)
)
)
),
));
<div oo-notification="success">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component.
</div>
You've created a success notification component.
# Creation from mixin
Combine the two mixins ooComponent()
and ooComponentVariant()
and develop your own Loop component after the initialization of the Loop config.
ooComponent($name){ @content }
Mixin - Create a base component
- $name (string) The name of the component
- @content CSS rules
@include ooComponent('notification') {
padding: 1rem;
border-left-width: 5px;
border-left-style: solid;
box-shadow: 4px 4px 8px rgba(0, 0, 0, .15);
}
ooComponentVariant($componentName, $variantName){ @content }
Mixin - Create a component variation
- $componentName (string) The name of the component
- $variantName (string) The name of the variant
- @content CSS rules
@include ooComponentVariant('notification', 'success') {
color: #015a31;
border-color: #83cca9;
background-color: #c8f7e1;
}
@include ooComponentVariant('notification', 'danger') {
color: #5a0101;
border-color: #ca7878;
background-color: #f7c8c8;
}
@include ooComponentVariant('notification', 'large') {
padding: 1.75rem 2rem;
font-size: 1.5rem;
strong {
font-weight: 900;
text-transform: uppercase;
letter-spacing: -.5px;
}
}
@include ooComponentVariant('notification', 'centered') {
text-align: center;
border-left: 0;
border-top-width: 5px;
border-top-style: solid;
}
<div oo-notification="success large">
<strong>Hey, well done!</strong><br>You've created a <i>success</i> notification component
</div>
You've created a success notification component.
<div oo-notification="danger">
<strong>Hey, well done!</strong><br>You've created a <i>danger</i> notification component.
</div>
You've created a danger notification component.
# Turn Utility First Component into Loop Component
Developing with utilities increases speed and help us prototyping rapidly custom components. As a result, we tend to add an incredible amount of single classes to a single html element to achieve a specific style. Repeating the same classes while making reusable modular code could easily start to be unproductive.
Take into condiseration setting aside utility-first-component for common group paterns and turn them into loop-component. Write less HTML with more CSS.
Example with the Event utility-first17 classes + 1 button component & 2 modifiers
<div class="bg-white text-center shape-squircle overflow-hidden shadow-tiny">
<time datetime="2020-09-07 10:00"
class="d-block wrapper-tiny bg-primary color-white font-small text-uppercase">
September 7th, 10am
</time>
<div class="wrapper-small wrapper-medium@md">
<h3 class="mt-0 mb-0">Frontend Developer Festival</h3>
<p class="text-wide">Tokyo, Odaiba, Big Sight</p>
<button class="shape-stadium" data-oo-button="primary outline">Join</button>
</div>
</div>
Frontend Developer Festival
Tokyo, Odaiba, Big Sight
// _config.scss
@import 'oo-loop/loop';
$ooLoop: ooSet('palette.alert': #f15f63);
$ooLoop: ooSet('button.outline', true);
$ooLoop: ooSet('button.variants.stadium', (
border-radius: 50em,
);
$ooLoop: ooSet('components', ('event': (
props: (
padding: (
rt: 1rem,
sm: 1.5rem,
),
overflow: hidden,
text-align: center,
background-color: #fff,
border-radius: 1em,
box-shadow: 0 1px 1px 0 rgba(0,0,0, .15),
'>': (
'time': (
padding: .5rem,
margin: (
rt: -1rem -1rem 1rem,
sm: -1.5rem -1.5rem 1.5rem,
),
display: block,
color:#fff,
font-size: rem(14),
text-transform: uppercase,
background-color: this('palette.primary'),
),
'h3': (
margin: 0,
),
'p': (
letter-spacing: .5px,
),
),
),
variants: (
'alert': (
'>': (
'time': (
background-color: this('palette.alert')
),
'h3::before': (
margin-bottom: 4px,
display: block,
content: '!!!Cancelled!!!',
font-size: 1rem,
color: this('palette.alert')
)
)
)
),
)));
@include ooCreate();
<div oo-event>
<time datetime="2020-09-07 10:00">September 7th, 10am</time>
<h3>Frontend Developer Festival</h3>
<p>Tokyo, Odaiba, Big Sight</p>
<button oo-button="primary stadium outline">Join</button>
</div>
<div oo-event="alert">
<time datetime="2020-09-07 10:00">September 8th, 10am</time>
<h3>Frontend Developer Festival</h3>
<p>Tokyo, Odaiba, Big Sight</p>
<button oo-button="alert stadium outline">Join</button>
</div>
0 class, 1 event component + 1 button component & 3 modifers
Frontend Developer Festival
Tokyo, Odaiba, Big Sight
Frontend Developer Festival
Tokyo, Odaiba, Big Sight