Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
July 14, 2020 05:07 pm GMT

Zen in the Art of the Expanding Search Bar

Take a minute and create a basic search bar. I mean really. Standard. Just an input and a button, maybe nest them inside a div if you're feeling generous. This search bar needs data to filter through and return, along with an event listener.

But you don't just stop there. You need the CSS to really make this search bar stand out. However, CSS is notoriously feral. It smells your fear, this is a fact. You have to tread carefully. The tutorials will feel like hell, I mean, you're learning all these things but in which situations would they best apply? Why would you use grid over flexbox? How does a margin just collapse? Why did this person use ::before and ::after. Why does position: absolute break everything? It's scary at first. Still is sometimes, if I can be completely honest.

Alt Text

The best way to get started is to imagine what you'd like your end result to be. I want a search bar with pseudo-elements, beautifully obnoxious borders, along with a smooth transition as it contracts and expands. This won't be a simple post about the many things one CSS property can do. This is more of a "here's nearly every CSS property you need to make this one component" walkthrough. So get ready, I'm about to explain to you all something I just taught myself last week.

Alt Text

One of the earliest habits I got into was giving every element a border: 1px solid [any random color];. Reflect back to how you drew the sun as a child, perhaps you drew the outline of the sun first, and then you filled it in with whatever shades of yellow and orange. This gives you a visual grasp of how things will sit in place.

A huge part of gorgeous CSS is structured HTML. In the HTML, I have three divs. An outer container, this could be your nav, I just use a regular div. Inside that is a wrapper, first-wrapper for both the search button and... another div, first-input-wrapper, which is specifically for the input. Click the search button, you'll see the div containing the input expands and contracts. Buried in all the sizing and positioning are two really important properties.

#first-input-wrapper { transition: width 1s;}

Transition

The transition is where the smooth animation comes from. Something is going to happen to this element-- like the eventListener that's going to alter its width. When that does happen, we want this transition of width from one size to the other to last 1 second. But it takes the input with it. Beneath that declaration is another for the input.

input { width: 100%;}

Width as a Percentage

This says the width of the input should be 100% of its parent container. While the parent container is 200px, it's full size. When it contracts to 0, so does the input.

Let's take this up a notch. For the design, I was inspired by this beautiful form. See how there's another div behind the form with the same sizing, offset by a few pixels, and they both have borders? This is really cute. I want that for our search bar.

Let's switch back to our code now. I've forked my codepen and applied some styling.

I know what you're thinking. Trust me, I didn't do much.

Pseudo-Elements

The way we can achieve that "stacked" look is by using pseudo-elements. Looking back at the form, it looks like there are two divs stacked on top of each other-- same for our input and our button. It looks like they're there. But check the HTML, you'll see they aren't. Pseudo-elements let you create a fake element that'll sit inside whatever element you choose.

You were probably wondering why I bolded specifically for the input earlier on. The rule of thumb is that elements with self-closing tags can't have pseudo-elements because they'll never have anything nested inside them. To get our styling to work, we need to wrap our input with a container element, like a div, and add a pseudo-element to that.

Let's break down the button first. We give it a background color of lime-green. Buttons come with outlines and borders by default, so you can set the border and outline to none, or override them with a specific border or outline. The height and width make it a perfect square. And the position relative...? We'll get to that.

button { background-color: #9ACB34; border: none; position: relative; width: 65px; height: 65px; outline: 3px solid #353E4A;}

When you make a pseudo-element, you can use ::before or ::after. It won't make much of a difference here here, but if you had text for your content, it'll make much more sense. ::before and ::after refer to the order in which that pseudo-element will appear, will it come before the content inside that element, or after? I left the content as an empty string, because we don't need any text, we just want to create the illusion of another div to sit behind the button. And we can do that by giving it the same height and width. Then we want to give it a z-index of -1 to push it behind, because pseudo-elements display inside the element, and in our case, it'll sit right on top.

position: wat;

First, let's make this easy, we say we want it 5px away from the top, and 5px away from the left. Now, million dollar question: why did I use position: absolute when it usually breaks everything?

When an element has a position of relative, it means you're setting it relative to its normal position, so you get the ability to set it any distance away from any direction away from where it normally sits. When an element has a position of absolute... it truly makes its own rules. It's supposed to position that element relative to its first positioned ancestor. If we didn't set the pseudo-button 5px away from the top and left, it would sit flush, right underneath our
real button-- and only flush because it's positioned relative to the real button. If it were any smaller, it would sit inside the button as if everything was perfectly normal, either before or after the content inside the real button, depending on if you used ::before or ::after.

button::before { content: ""; position: absolute; background-color: #FBF8EF; height: 65px; width: 65px; top: 5px; left: 5px; outline: 3px solid #353E4A; z-index: -1;}

Without the styling, the boilerplate for a pseudo-element looks like this. Then you would be able to add your own sizing along with positioning in any direction as you see fit. The same manipulations you would apply to your regular div, you can also do here.

div {  position: relative;}div::before {  content: "";  position: absolute;  z-index: -1;}

Now that the button looks pretty, we need to set up the input.

input { width: 100%; border: none; outline: none; height: 100%; background-color: #9ACB34;}

Like buttons, inputs also come with default borders and outlines that you can override. Also, give it a height of 100%, because it sits inside first-input-wrapper, and we'd like it to take up 100% of the height of first-input-wrapper. Annnnnd give it a background color too.

But... first-input-wrapper has a pseudo-element. It's not much different than the button.

#first-input-wrapper { transition: width 1s; height: 65px; width: 200px; position: relative; outline: 3px solid #353E4A;}#first-input-wrapper::before { content: ""; position: absolute; height: 65px; width: 100%; top: 5px; left: 5px; z-index: -1; outline: 3px solid #353E4A;}

Well... except for its width. We want the container to expand and contract. And all elements within it to follow. The input has a width of 100%. The pseudo-element we create for first-input-wrapper still sits within it, even though it looks like it doesn't. It's an illusion all the way, but the best way to see how this works is by swapping out the width for 200px. Click the search button and you'll see what while first-input-wrapper contracts, and the input disappears, there is an overflow of the pseudo-element that remains. You want that to take up 100% of first-input-wrapper, so when it contracts, the pseudo-element disappears too.

We're almost ready to take off our training wheels (read: borders). What's next? I don't want this to sit in the center of a container. When it contracts, the search button goes right to the center, because of the display: flex and justify-content: center; properties that #first-wrapper has. Also, I want it to sit on the right side of the page. I'm real proud of this, but no need for it to sit front and center. ALSO... Instead of search, I need a cute magnifying glass icon, followed by an arrow icon, and they'll toggle based on whether the search bar is expanded or contracted. Also, the input needs a little padding, and a placeholder. Also... let's get a font in here too!

See how this expanded completely? This whole process, for a search bar. That's why I made this a whole walkthrough, because just knowing what you can do with any specific property is the first step, and usually the most overwhelming, but knowing how these specific properties can work together is really where the magic comes from.

Let's press on. I forked my codepen, and added more styles. We're going to go through it again.

Some changes have been made to the containers we just had borders on. I gave first-container a position of relative, because we'll need to give first-wrapper a position of absolute. What this is going to accomplish is give us a way to push this search bar all the way to the right.

Then, in first-wrapper, there are some new styles.

 width: fit-content; position: absolute; right: 0;

I don't know what the combined width of first-input-wrapper along with the button is. It's not important, but I want the width of first-wrapper to automatically fit that, no matter what size its children are. Throw a border on that to test it out, and you'll see it's almost the opposite of using width as a percentage, so instead of the children taking up the whole heart of the parent, the parent is now expanding its heart for its children! Silly analogy, I know, but the parent and child analogies for DOM manipulation are really adorable.

How does this all work together? first-input-wrapper is going to contract and expand, leaving the button, fine. We want the parent container, first-wrapper, to shrink along with it, and to not hold any space. But we also want this to stay put on the right, no matter what state it's in.

background-image: url();

Now, the icons. Look for any PNG or SVG that interests you. I like using SVGs because you can scale them to any size without losing quality.

 background-image: url('[throw your link in here!]'); background-size: 50%; background-repeat: no-repeat;  background-position: center; transition: background-image .3s;

So our search button has a "Search" text no more-- now its a cute magnifying glass, that didn't start out so cute. At first, it was kind of large, so we want it to take up 50% of the size of the button. But when you do that, you'll notice it repeats itself, so we want to disable that. Then when you decrease the size, the position will be off, so we give it a position of center to sit... flush. Then there's another transition-- .3s for the background-image.

Let's switch gears into the JavaScript now. The event listener. We see how the width for inputDiv gets toggled on click. This is how I also want to toggle the icons.

With the same logic that I use to toggle the width of first-input-wrapper, we can also change the background-image of the button.

  btn.style.backgroundImage = "url('[add your link here]')"  // have one of these in your if statement with the first image  // and the other in your else with the other image you want to toggle to. 

We're almost at the finish line... just some minor tweaks to make to the input field. We need a font and some padding. Look at the first few versions of this search bar, try typing some text in there, you'll see there's no space between the text and the absolute end of the input on the left. Adding some padding means you're going to give space between the bounds of the element, and its children. But we don't need to give this padding on all sides, just the left.

input { padding-left: 10px;}

Last tweak, I promise... the font. I've been really liking the IBM Plex Mono font from Google Fonts. Sure we can add this in our input as the font-family, but what about the placeholder? How do you target that?

input::placeholder { color: #353E4A;}

By using the CSS pseudo-class of ::placeholder. So we're targeting the special state of an element-- an input with a placeholder. And that's how we can change the text color.

Ok, breathe. We're done. We did it. There you have it. An expanding search bar with logic of its own, and nearly every minor detail handled with the greatest amount of care and attention.


Original Link: https://dev.to/ddel/zen-in-the-art-of-the-expanding-search-bar-2mmb

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To