SwifWeb and How to Center the Div!

Written by imike | Published 2023/03/23
Tech Story Tags: swift | webassembly | tutorial | css | autolayout | webdev | programming | coding

TLDRA typical challenge in the world of web development is how to effectively layout elements on the screen. Since the classic CSS layout paradigm can be frustrating at times, I realized that I needed a library to simplify the process. After spending a few days on it, I created the Autolayout library. This powerful tool gives you infinite power in UI development, making your web development experience much simpler.via the TL;DR App

Laying out elements on the screen is always a challenge for web developers.

Nobody remembers how to do it, especially vertically šŸ˜ because it is not as simple as in mobile development, it is different.

Every time I switch to web development I miss the autolayout feature, classic CSS layout paradigm literally makes me cry sometimes, so at some point I decided that I have to have some library that can make my web dev life much simpler. I spent few days making one and named it Autolayout šŸ“

The first idea was to make it work exactly the same way as constraints work on iOS. I was so sure that it was possible, so I started working on it and implemented it. It worked great until I had only a few elements on the screen. However, with a lot of elements, I faced a huge amount of redraws. So, I realized there was an issue and accepted defeat, at least for the time being.

Hereā€™s the branch with it.

But did I give up? No!

It is art for me and I had to build a great solution to keep my code beautiful and easy to maintain!

I implemented autolayout in pure CSS!

Well not everything. It doesnā€™t have an ability to stick side or size to another view since CSS doesnā€™t have mechanisms for that. But it is something on the same level! Just take a look!

So How Does It Work?

  • First, you can do basic and complex things declaratively.
  • Second, instead of building complex @media rules, you can now declare them inline.
  • Also Autolayout takes care of solving complex overriding priority issues behind the scenes.

Letā€™s assume you have a Div and you want to set the width to 600px.

Div().width(600.px)

But now you want to have a different width for different screen sizes.

Div().width(600.px) // will be used for extra large screens
     .width(200.px, breakpoints: .xs, .s) // for extra small and small screens
     .width(400.px, breakpoints: .m, .l) // for medium and large screens

Got the idea? Yeah itā€˜s cool! But now you probably want to know more about the breakpoints.

Breakpoints

.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

Yeah, it's a classic pattern that you may have seen before in Bootstrap or other UI frameworks.

You also 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.

Otherwise it will use just the whole rule text.

Breakpoints can be added to the end of any autolayout-method.

.top(100.px, breakpoints: .extraSmall, .small, .medium)

And you can use breakpoints within the classic stylesheet.

Stylesheet {
    Rule(Body.pointer)
        .margin(all: 0.px)
        .padding(all: 0.px)
    MediaRule(.extraSmall, .small) { // will be applied only for extra-small and small screens
        Rule(Body.pointer)
            .backgroundColor(0x9bc4e2)
    }
    MediaRule(.medium, .large, .extraLarge) { // will be applied only for medium, large, and extra-large screens
        Rule(Body.pointer)
            .backgroundColor(0xffd700)
    }
}

What Methods Are Available?

Size

All of the methods have breakpoints: as a last argument.

width and height are simple, I just added widthToParent and heightToParent convenience methods to be able to expand the view to its parent size.

Sides

Letā€™s talk about top, right, bottom, left.

Please just keep in mind that these methods donā€™t work with static position.

Sticking the view to the certain sides:

.top()    // will set top    to 0px
.bottom() // will set bottom to 0px
.left()   // will set left   to 0px
.right()  // will set right  to 0px

All of the methods above can be used with a value and reactive @State value.

// will set top to 0px only for extra-small, small and medium screens
.top(breakpoints: .xs, .s, .m)

.top(100.px)                  // will set top to 100px
.top(100.px, multiplier: 0.5) // will set top to 50px

// 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)

Same for bottom, left, and right.

But there are extra convenience methods!

You can stick all of these sides to the center of parent or to the opposite side.

Letā€™s take a look at the top to center and top to bottom examples:

.top(side: .center)         // will set top to 0px   from the center
.top(100.px, side: .center) // will set top to 100px from the center

// 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)

// multiplier is also available

Top can stick to center and bottom

Bottom can stick to center and top

Left can stick to center and right

Right can stick to center and left

I believe you got the idea! šŸ˜€

But that is not all! I have more convenient methods for you!

All sides

// All sides
.edges()      // will set top, right, bottom, and left to 0px
.edges(10.px) // will set top, right, bottom, and left to 10px
.edges(5.px, breakpoints: .xs, .s, .m) // you know, only for certain screens

Horizontal

.edges(h: 0.px)  // left and right to 0px
.edges(h: 10.px) // left and right to 10px
.edges(h: 5.px, breakpoints: .xs, .s, .m)

Vertical

.edges(v: 0.px)  // top and bottom to 0px
.edges(v: 10.px) // top and bottom to 10px
.edges(v: 5.px, breakpoints: .xs, .s, .m)

Both

.edges(h: 0.px, v: 0.px)  // left and right to 0px, and top and bottom to 0px
.edges(h: 0.px, v: 10.px) // left and right to 0px, and top and bottom to 10px
.edges(h: 2.px, v: 4.px, breakpoints: .xs, .s, .m)

Centering

Finally! So how to center the Div? šŸ˜ šŸ˜ šŸ˜

Not that fast, we usually pronounce X and Y, so horizontal centering first! šŸ˜

Center X

.centerX()       // will set centerX to 0px
.centerX(100.px) // will set centerX to 100px

.centerX(breakpoints: .xs, .s, .m) // center horizontally only for certain screens
.centerX(50.px, breakpoints: .xs, .s, .m)

Center Y (yeah!)

.centerY()       // will set centerY to 0px
.centerY(100.px) // will set centerY to 100px

.centerY(breakpoints: .xs, .s, .m) // center vertically only for certain screens
.centerY(50.px, breakpoints: .xs, .s, .m)

Also with side: extra argument!

.left and .right for horizontal

.centerX(side: .left)          // centerX to 0px   of the left
.centerX(100.px, side: .right) // centerX to 100px of the right
.centerX(side: .left, breakpoints: .xs, .s, .m)
.centerX(50.px, side: .left, breakpoints: .xs, .s, .m)

.top and .bottom for vertical

.centerY(side: .top)            // centerY to 0px   of the top
.centerY(100.px, side: .bottom) // centerY to 100px of the bottom
.centerY(side: .top, breakpoints: .xs, .s, .m)
.centerY(50.px, side: .top, breakpoints: .xs, .s, .m)

Center for both X and Y

.center()       // centerX and centerY to 0px
.center(100.px) // centerX and centerY to 100px

.center(breakpoints: .xs, .s, .m) // centerX and centerY to 0px only certain screens
.center(50.px, breakpoints: .xs, .s, .m) // you got the idea!

Yeah, you should already feel the infinite power! šŸ˜Ž

Positioning

Control the type of positioning likeĀ static, relative, absolute, fixed with the breakpoints:

// set the position to absolute
.position(.absolute)
// set the position to fixed for certain screens
.position(.fixed, breakpoints: .xs, .s, .m)

Visibility

Display

.display(.block)
.display(.none, breakpoints: .xs, .s, .m)

Visibility

.visibility(.visible)
.visibility(.hidden, breakpoints: .xs, .s, .m)

Opacity

.opacity(1)
.opacity(0, breakpoints: .xs, .s, .m)

Does It Work With LivePreview?

Yes! I know you really need it during the prototyping!

To make it work just add into Preview.Content either:

AppStyles.all or AppStyles.id(.autolayoutStyles)

How To Install the Library?

If you are new to SwifWeb then you have to create a new project using the Webber CLI tool.

In the project open Package.swift and edit dependencies section to make it look like this:

dependencies: [
    // the rest of the other dependencies incuding swifweb/web
    .package(url: "https://github.com/swifweb/autolayout", from: "1.0.0"),
]

Then edit executableTarget to make it look like this:

.executableTarget(name: "App", dependencies: [
    .product(name: "Web", package: "web"),
    .product(name: "Autolayout", package: "autolayout")
]),

Next, just import Autolayout where needed.

Thatā€™s it!

Wanna learn more? Stay tuned for the upcoming articles!

Donā€™t hesitate to ask any questions in our Discord and feel free to contribute!


Written by imike | Swift Evangelist
Published by HackerNoon on 2023/03/23