This library gives you the powerful autolayout which works on pure CSS3 β€οΈ
It will help you to easily build your awesome reactive web app in beloved Swift β€οΈ
Add package to your SwifWeb app's Package.swift
In dependencies section
dependencies: [
.package(url: "https://github.com/swifweb/autolayout", from: "1.0.3")
]
In target section
targets: [
.executableTarget(name: "App", dependencies: [
.product(name: "Web", package: "web"),
.product(name: "Autolayout", package: "autolayout")
]
]
Instead of building complex @media
rules in stylesheets you now can do same inline declaratively.
Under the hood autolayout takes care about solving complex overriding priority issues.
import Autolayout
// amazingly laconic and powerful
Div()
.position(.relative)
.position(.absolute) // it will override relative with absolute for extra-small and small screens
.height(100.px)
.top()
.backgroundColor(.brown)
.widthToParent() // which is width: 100%
.width(100.px, breakpoints: .xs, .s) // it will override 100% to 100px for extra-small and small screens
.edges(h: 0.px) // which is left: 0px, right: 0px
.centerX(breakpoints: .xs, .s) // it will disable right, and will set left: 50%, translate-x: -50% for extra-small and small screens
.opacity(0.8, breakpoints: .xs, .s) // it will set opacity: 0.8 for extra-small and small screens
Start using it at any view by simply declaring methods listed below. But first read about breakpoints.
Normally we have to declare @media
rules in a stylesheet, and it takes a lot of time.
With autolayout you could declare breakpoints (aka @media
rules) once and use it as an alias.
There are predefined breakpoints for you:
.xs or .extraSmall // <576px
.s or .small // β₯576px and <768px
.m or .medium // β₯768px and <992px
.l or .large // β₯992px and <1200px
.xl or .extraLarge // β₯1200px and <1400px
.xxl or .extraExtraLarge // β₯1400px
or you can declare your own (just notice how long they are):
extension MediaRule.MediaType {
static var extraSmall: MediaRule.MediaType { .init(.all.maxWidth(575.px), label: "xs") }
static var small: MediaRule.MediaType { .init(.all.minWidth(576.px).maxWidth(767.px), label: "s") }
static var medium: MediaRule.MediaType { .init(.all.minWidth(768.px).maxWidth(991.px), label: "m") }
}
use
label: "xs"
to prettify your breakpoint in the source code, cause otherwise it will use just the whole rule text
Breakpoints can be added in the end of any autolayout-method. It uses full power of CSS3 @media
rule under the hood.
.top(100.px, breakpoints: .extraSmall, .small, .medium)
Or you can use breakpoints within the classic stylesheet
@DOM override var body: DOM.Content {
Stylesheet {
Rule(Body.pointer)
.margin(all: 0.px)
.padding(all: 0.px)
MediaRule(.xs, .s) { // will be applied only for extra-small and small screens
Rule(Body.pointer)
.backgroundColor(0x9bc4e2)
}
MediaRule(.m, .l, .xl) { // will be applied only for medium, large, and extra-large screens
Rule(Body.pointer)
.backgroundColor(0xffd700)
}
}
// ...other elements...
}
You can declare different values for the same property but with different breakpoints
// will be applied in any case
.width(600.px)
// will override any other values when screen width is extra-small or small
.width(200.px, breakpoints: .xs, .s)
// will override any other values when screen width is medium or large
.width(400.px, breakpoints: .m, .l)
The library will take care of overriding priority.
top, right, bottom, left, center, width, height
methods relate to position
property of the element and of its parent
if you want to set these properties globally (to the window boundaries) then use
.position(.absolute) // or .fixed, .sticky
if you want to set these properties relative to its parent then use
.position(.relative)
and don't forget that that's parent also should have
.position(.relative)
or the parent of its parent and so on
Please don't forget that with
.position(.static) // or if position haven't been set at all
only width
and height
property works, other properties just can't work in this case
Each method also can be used with
@State
value
Specifies top
position to the first parent element with relative position
// will set top to 0px
.top()
// will set top to 100px
.top(100.px)
// will set top to 50px
.top(100.px, multiplier: 0.5)
// will set top to 0px only for extra-small, small and medium screens
.top(breakpoints: .xs, .s, .m)
// will set top to 50px only for extra-small, small and medium screens
.top(50.px, breakpoints: .xs, .s, .m)
// will set top to 25px only for extra-small, small and medium screens
.top(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .center
as a second argument and top
side will stick to center
of the first parent with relative position
// will set top to 0px from the center
.top(side: .center)
// will set top to 100px from the center
.top(100.px, side: .center)
// will set top to 50px from the center
.top(100.px, side: .center, multiplier: 0.5)
// will set top to 0px from the center only for extra-small, small and medium screens
.top(side: .center, breakpoints: .xs, .s, .m)
// will set top to 50px from the center only for extra-small, small and medium screens
.top(50.px, side: .center, breakpoints: .xs, .s, .m)
// will set top to 25px from the center only for extra-small, small and medium screens
.top(50.px, side: .center, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .bottom
as a second argument and top
side will stick to bottom
of the first parent with relative position
// will set top to 0px from the bottom
.top(side: .bottom)
// will set top to 100px from the bottom
.top(100.px, side: .bottom)
// will set top to 50px from the bottom
.top(100.px, side: .bottom, multiplier: 0.5)
// will set top to 0px from the bottom only for extra-small, small and medium screens
.top(side: .bottom, breakpoints: .xs, .s, .m)
// will set top to 50px from the bottom only for extra-small, small and medium screens
.top(50.px, side: .bottom, breakpoints: .xs, .s, .m)
// will set top to 25px from the bottom only for extra-small, small and medium screens
.top(50.px, side: .bottom, multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies bottom
position to the first parent element with relative position
// will set bottom to 0px
.bottom()
// will set bottom to 100px
.bottom(100.px)
// will set bottom to 50px
.bottom(100.px, multiplier: 0.5)
// will set bottom to 0px only for extra-small, small and medium screens
.bottom(breakpoints: .xs, .s, .m)
// will set bottom to 50px only for extra-small, small and medium screens
.bottom(50.px, breakpoints: .xs, .s, .m)
// will set bottom to 25px only for extra-small, small and medium screens
.bottom(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .center
as a second argument and bottom
side will stick to center
of the first parent with relative position
// will set bottom to 0px from the center
.bottom(side: .center)
// will set bottom to 100px from the center
.bottom(100.px, side: .center)
// will set bottom to 50px from the center
.bottom(100.px, side: .center, multiplier: 0.5)
// will set bottom to 0px from the center only for extra-small, small and medium screens
.bottom(side: .center, breakpoints: .xs, .s, .m)
// will set bottom to 50px from the center only for extra-small, small and medium screens
.bottom(50.px, side: .center, breakpoints: .xs, .s, .m)
// will set bottom to 25px from the center only for extra-small, small and medium screens
.bottom(50.px, side: .center, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .top
as a second argument and bottom
side will stick to top
of the first parent with relative position
// will set bottom to 0px from the top
.bottom(side: .top)
// will set bottom to 100px from the top
.bottom(100.px, side: .top)
// will set bottom to 50px from the top
.bottom(100.px, side: .top, multiplier: 0.5)
// will set bottom to 0px from the top only for extra-small, small and medium screens
.bottom(side: .top, breakpoints: .xs, .s, .m)
// will set bottom to 50px from the top only for extra-small, small and medium screens
.bottom(50.px, side: .top, breakpoints: .xs, .s, .m)
// will set bottom to 25px from the top only for extra-small, small and medium screens
.bottom(50.px, side: .top, multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies left
position to the first parent element with relative position
// will set left to 0px
.left()
// will set left to 100px
.left(100.px)
// will set left to 50px
.left(100.px, multiplier: 0.5)
// will set left to 0px only for extra-small, small and medium screens
.left(breakpoints: .xs, .s, .m)
// will set left to 50px only for extra-small, small and medium screens
.left(50.px, breakpoints: .xs, .s, .m)
// will set left to 25px only for extra-small, small and medium screens
.left(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .center
as a second argument and left
side will stick to center
of the first parent with relative position
// will set left to 0px from the center
.left(side: .center)
// will set left to 100px from the center
.left(100.px, side: .center)
// will set left to 50px from the center
.left(100.px, side: .center, multiplier: 0.5)
// will set left to 0px from the center only for extra-small, small and medium screens
.left(side: .center, breakpoints: .xs, .s, .m)
// will set left to 50px from the center only for extra-small, small and medium screens
.left(50.px, side: .center, breakpoints: .xs, .s, .m)
// will set left to 25px from the center only for extra-small, small and medium screens
.left(50.px, side: .center, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .right
as a second argument and left
side will stick to right
of the first parent with relative position
// will set left to 0px from the right
.left(side: .right)
// will set left to 100px from the right
.left(100.px, side: .right)
// will set left to 50px from the right
.left(100.px, side: .right, multiplier: 0.5)
// will set left to 0px from the right only for extra-small, small and medium screens
.left(side: .right, breakpoints: .xs, .s, .m)
// will set left to 50px from the right only for extra-small, small and medium screens
.left(50.px, side: .right, breakpoints: .xs, .s, .m)
// will set left to 25px from the right only for extra-small, small and medium screens
.left(50.px, side: .right, multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies right
position to the first parent element with relative position
// will set right to 0px
.right()
// will set right to 100px
.right(100.px)
// will set right to 50px
.right(100.px, multiplier: 0.5)
// will set right to 0px only for extra-small, small and medium screens
.right(breakpoints: .xs, .s, .m)
// will set right to 50px only for extra-small, small and medium screens
.right(50.px, breakpoints: .xs, .s, .m)
// will set right to 25px only for extra-small, small and medium screens
.right(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .center
as a second argument and right
side will stick to center
of the first parent with relative position
// will set right to 0px from the center
.right(side: .center)
// will set right to 100px from the center
.right(100.px, side: .center)
// will set right to 50px from the center
.right(100.px, side: .center, multiplier: 0.5)
// will set right to 0px from the center only for extra-small, small and medium screens
.right(side: .center, breakpoints: .xs, .s, .m)
// will set right to 50px from the center only for extra-small, small and medium screens
.right(50.px, side: .center, breakpoints: .xs, .s, .m)
// will set right to 25px from the center only for extra-small, small and medium screens
.right(50.px, side: .center, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .left
as a second argument and right
side will stick to left
of the first parent with relative position
// will set right to 0px from the left
.right(side: .left)
// will set right to 100px from the left
.right(100.px, side: .left)
// will set right to 50px from the left
.right(100.px, side: .left, multiplier: 0.5)
// will set right to 0px from the left only for extra-small, small and medium screens
.right(side: .left, breakpoints: .xs, .s, .m)
// will set right to 50px from the left only for extra-small, small and medium screens
.right(50.px, side: .left, breakpoints: .xs, .s, .m)
// will set right to 25px from the left only for extra-small, small and medium screens
.right(50.px, side: .left, multiplier: 0.5, breakpoints: .xs, .s, .m)
Convenience setter for all sides: top, right, bottom, left
// Will set top, right, bottom, and left to 0px
.edges()
// Will set top, right, bottom, and left to 10px
.edges(10.px)
// Will set top, right, bottom, and left to 5px only for extra-small, small and medium screens
.edges(5.px, breakpoints: .xs, .s, .m)
// Will set left and right to 0px
.edges(h: 0.px)
// Will set left and right to 10px
.edges(h: 10.px)
// Will set left and right to 5px only for extra-small, small and medium screens
.edges(h: 5.px, breakpoints: .xs, .s, .m)
// Will set top and bottom to 0px
.edges(v: 0.px)
// Will set top and bottom to 10px
.edges(v: 10.px)
// Will set top and bottom to 5px only for extra-small, small and medium screens
.edges(v: 5.px, breakpoints: .xs, .s, .m)
// Will set left and right to 0px, and top and bottom to 0px
.edges(h: 0.px, v: 0.px)
// Will set left and right to 0px, and top and bottom to 10px
.edges(h: 0.px, v: 10.px)
// Will set left and right to 2px, and top and bottom to 4px only for extra-small, small and medium screens
.edges(h: 2.px, v: 4.px, breakpoints: .xs, .s, .m)
Specifies the horizontal center position to the first parent element with relative position
// will set centerX to 0px
.centerX()
// will set centerX to 100px
.centerX(100.px)
// will set centerX to 50px
.centerX(100.px, multiplier: 0.5)
// will set centerX to 0px only for extra-small, small and medium screens
.centerX(breakpoints: .xs, .s, .m)
// will set centerX to 50px only for extra-small, small and medium screens
.centerX(50.px, breakpoints: .xs, .s, .m)
// will set centerX to 25px only for extra-small, small and medium screens
.centerX(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .left
as a second argument and centerX
side will stick to left
of the first parent with relative position
// will set centerX to 0px of the left
.centerX(side: .left)
// will set centerX to 100px of the left
.centerX(100.px, side: .left)
// will set centerX to 50px of the left
.centerX(100.px, side: .left, multiplier: 0.5)
// will set centerX to 0px of the left only for extra-small, small and medium screens
.centerX(side: .left, breakpoints: .xs, .s, .m)
// will set centerX to 50px of the left only for extra-small, small and medium screens
.centerX(50.px, side: .left, breakpoints: .xs, .s, .m)
// will set centerX to 25px of the left only for extra-small, small and medium screens
.centerX(50.px, side: .left, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .right
as a second argument and centerX
side will stick to right
of the first parent with relative position
// will set centerX to 0px of the right
.centerX(side: .right)
// will set centerX to 100px of the right
.centerX(100.px, side: .right)
// will set centerX to 50px of the right
.centerX(100.px, side: .right, multiplier: 0.5)
// will set centerX to 0px of the right only for extra-small, small and medium screens
.centerX(side: .right, breakpoints: .xs, .s, .m)
// will set centerX to 50px of the right only for extra-small, small and medium screens
.centerX(50.px, side: .right, breakpoints: .xs, .s, .m)
// will set centerX to 25px of the right only for extra-small, small and medium screens
.centerX(50.px, side: .right, multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies the vertical center position to the first parent element with relative position
// will set centerY to 0px
.centerY()
// will set centerY to 100px
.centerY(100.px)
// will set centerY to 50px
.centerY(100.px, multiplier: 0.5)
// will set centerY to 0px only for extra-small, small and medium screens
.centerY(breakpoints: .xs, .s, .m)
// will set centerY to 50px only for extra-small, small and medium screens
.centerY(50.px, breakpoints: .xs, .s, .m)
// will set centerY to 25px only for extra-small, small and medium screens
.centerY(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .top
as a second argument and centerY
side will stick to top
of the first parent with relative position
// will set centerY to 0px of the top
.centerY(side: .top)
// will set centerY to 100px of the top
.centerY(100.px, side: .top)
// will set centerY to 50px of the top
.centerY(100.px, side: .top, multiplier: 0.5)
// will set centerY to 0px of the top only for extra-small, small and medium screens
.centerY(side: .top, breakpoints: .xs, .s, .m)
// will set centerY to 50px of the top only for extra-small, small and medium screens
.centerY(50.px, side: .top, breakpoints: .xs, .s, .m)
// will set centerY to 25px of the top only for extra-small, small and medium screens
.centerY(50.px, side: .top, multiplier: 0.5, breakpoints: .xs, .s, .m)
Simply add side: .bottom
as a second argument and centerY
side will stick to bottom
of the first parent with relative position
// will set centerY to 0px of the bottom
.centerY(side: .bottom)
// will set centerY to 100px of the bottom
.centerY(100.px, side: .bottom)
// will set centerY to 50px of the bottom
.centerY(100.px, side: .bottom, multiplier: 0.5)
// will set centerY to 0px of the bottom only for extra-small, small and medium screens
.centerY(side: .bottom, breakpoints: .xs, .s, .m)
// will set centerY to 50px of the bottom only for extra-small, small and medium screens
.centerY(50.px, side: .bottom, breakpoints: .xs, .s, .m)
// will set centerY to 25px of the bottom only for extra-small, small and medium screens
.centerY(50.px, side: .bottom, multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies both vertical and horizontal center position to the first parent element with relative position
// will set centerX and centerY to 0px
.center()
// will set centerX and centerY to 100px
.center(100.px)
// will set centerX and centerY to 50px
.center(100.px, multiplier: 0.5)
// will set centerX and centerY to 0px only for extra-small, small and medium screens
.center(breakpoints: .xs, .s, .m)
// will set centerX and centerY to 50px only for extra-small, small and medium screens
.center(50.px, breakpoints: .xs, .s, .m)
// will set centerX and centerY to 25px only for extra-small, small and medium screens
.center(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Sets width of an element
// will set width to 0px
.width()
// will set width to 100px
.width(100.px)
// will set width to 100%
.width(100.percent)
// will set width to 50px
.width(100.px, multiplier: 0.5)
// will set width to 0px only for extra-small, small and medium screens
.width(breakpoints: .xs, .s, .m)
// will set width to 50px only for extra-small, small and medium screens
.width(50.px, breakpoints: .xs, .s, .m)
// will set width to 25px only for extra-small, small and medium screens
.width(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Sets width of an element to fit first parent element with relative position
// will set width to 100% of first parent element with relative position
.widthToParent()
// will set width to 100% of first parent element with relative position only for extra-small, small and medium screens
.widthToParent(breakpoints: .xs, .s, .m)
// will set width to 100% + 100px of first parent element with relative position
.widthToParent(extra: 100.px)
// will set width to 100% + 100px of first parent element with relative position
// only for extra-small, small and medium screens
.widthToParent(extra: 100.px, breakpoints: .xs, .s, .m)
// will set width to (100% + 100px) * 0.5 of first parent element with relative position
.widthToParent(extra: 100.px, multiplier: 0.5)
// will set width to (100% + 100px) * 0.5 of first parent element with relative position
// only for extra-small, small and medium screens
.widthToParent(extra: 100.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
// will set width to 50% of first parent element with relative position
.widthToParent(multiplier: 0.5)
// will set width to 50% of first parent element with relative position
// only for extra-small, small and medium screens
.widthToParent(multiplier: 0.5, breakpoints: .xs, .s, .m)
Sets height of an element
// will set height to 0px
.height()
// will set height to 100px
.height(100.px)
// will set height to 100%
.height(100.percent)
// will set height to 50px
.height(100.px, multiplier: 0.5)
// will set height to 0px only for extra-small, small and medium screens
.height(breakpoints: .xs, .s, .m)
// will set height to 50px only for extra-small, small and medium screens
.height(50.px, breakpoints: .xs, .s, .m)
// will set height to 25px only for extra-small, small and medium screens
.height(50.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
Sets height of an element to fit first parent element with relative position
// will set height to 100% of first parent element with relative position
.heightToParent()
// will set height to 100% of first parent element with relative position only for extra-small, small and medium screens
.heightToParent(breakpoints: .xs, .s, .m)
// will set height to 100% + 100px of first parent element with relative position
.heightToParent(extra: 100.px)
// will set height to 100% + 100px of first parent element with relative position
// only for extra-small, small and medium screens
.heightToParent(extra: 100.px, breakpoints: .xs, .s, .m)
// will set height to (100% + 100px) * 0.5 of first parent element with relative position
.heightToParent(extra: 100.px, multiplier: 0.5)
// will set height to (100% + 100px) * 0.5 of first parent element with relative position
// only for extra-small, small and medium screens
.heightToParent(extra: 100.px, multiplier: 0.5, breakpoints: .xs, .s, .m)
// will set height to 50% of first parent element with relative position
.heightToParent(multiplier: 0.5)
// will set height to 50% of first parent element with relative position
// only for extra-small, small and medium screens
.heightToParent(multiplier: 0.5, breakpoints: .xs, .s, .m)
Specifies the type of positioning method used for an element static, relative, absolute or fixed
// will set position to absolute
.position(.absolute)
// will set position to absolute only for extra-small, small and medium screens
.position(.absolute, breakpoints: .xs, .s, .m)
Specifies how a certain HTML element should be displayed
// will set display to block
.display(.block)
// will set display to block only for extra-small, small and medium screens
.display(.block, breakpoints: .xs, .s, .m)
Specifies whether or not an element is visible
// will set visibility to visible
.visibility(.visible)
// will set visibility to hidden only for extra-small, small and medium screens
.visibility(.hidden, breakpoints: .xs, .s, .m)
Sets the opacity level for an element
// will set opacity to 0.8
.opacity(0.8)
// will set opacity to 0.5 only for extra-small, small and medium screens
.opacity(0.5, breakpoints: .xs, .s, .m)
To make it work with live preview you need to specify either all styles or exact autolayout's one
class Welcome_Preview: WebPreview {
override class var title: String { "Initial page" } // optional
override class var width: UInt { 440 } // optional
override class var height: UInt { 480 } // optional
@Preview override class var content: Preview.Content {
// add styles if needed
AppStyles.all
// add here as many elements as needed
WelcomeViewController()
}
}
class Welcome_Preview: WebPreview {
override class var title: String { "Initial page" } // optional
override class var width: UInt { 440 } // optional
override class var height: UInt { 480 } // optional
@Preview override class var content: Preview.Content {
// add styles if needed
AppStyles.id(.mainStyle)
AppStyles.id(.autolayoutStyles)
// add here as many elements as needed
WelcomeViewController()
}
}