Need Help positioning my connect four board with CSS

#1

Hey friends. I’m trying to make a connect four game in JS and it took me a while to position the board where I want it. I was eventually able to do it using flexbox. I then wanted to add a red chip that would hover over the board like this

I was able to position this using position: relative, which I now know isn’t really smart.
So this time around i want to position the chip using flexbox. The problem is when I place the div that represents the chip above the board it moves the board up and over to the right?

This is what my new version looked like before I started to make that chip

Then I added the div.chip to the html and added flex-direction: column; to the CSS in an attempt to straighten everything back up, which didn’t work so now I have this

Any help on this issue would be greatly appreciated, Thanks:)

https://jsfiddle.net/3cdu0tyo/?utm_source=website&utm_medium=embed&utm_campaign=3cdu0tyo

0 Likes

#2

Have you ever completed a course in basic HTML and CSS?

The issues that you are having with your layout are very fundamental. Your code is written and formatted unusually well and you are not asking your layout to do anything unreasonable, therefore it seems that your knowledge of the fundamentals of HTML and CSS seem to be incomplete. What’s up?

0 Likes

#3

No it doesn’t !

The board is already to the right. Remove .outer-chip and you will see the board remains to the right. Adding outer-chip does not affect anything in the code you have shown.

The board is aligned to the right because you have set it to display there by this rule in the body tag.

body {
	align-items: flex-end;
}

That has nothing to do with outer-chip at all.:slight_smile:

Just for fun I put up a codepen that does the hover effects without js.

https://codepen.io/paulobrien/full/QPNXJg

I’m not saying this is the way to do it but just to give you other ideas. It alsoe should be made responsive and not rely on magic numbers but that would be possible with a little more work.

I’m not sure a table is semantic for a game unless you can ensure the relationship between the counters is made obvious in some ways. I feel that it may just be too hard to do where you have rows columns and diagonals that need to be in a relationship that assisted technologies could identify.

0 Likes

#4

@PaulOB the align-items: flex-end; was so I could push the game board to the bottom of the webpage. removing it will stretch the board the full width of the screen? still leaving that gap(which looks to have the same height as that red bar) underneath the board. I need the bottom of the board touching the bottom of the page and it needs to be centered. I will then focus turning that red bar into a chip

0 Likes

#5

I have completed that course, I might not have remembered eveything I’ve learned though. What specifically looks funky to you. And would happen to know a solution that would move the board to the center and bottom of the page? I’ll I know is position: relative/absolute; which I don’t wanna use and flexbox with justify content and align items which isn’t working?

0 Likes

#6

I just scrapped everything and copied your code pen. I really don’t understand most of the css so if you could give me a detailed explanation of the code listed below I’d appreciate it.

1. *, *:before, *:after {
	box-sizing: inherit;
}

2. .connect > div:not(.counter):after {
	content:"";
	z-index:-1;
	position:absolute;
	left:0;
	right:0;
	top:-999em;
	bottom:-999em;
	background:transparent;
	transition: all 0.5s ease;
}

3. .connect > div.counter:after {
	content:"";
	display:block;
	padding:0;
	position:absolute;
	z-index:100;
	top:0px;
	left:0;
	right:auto;
	height:40px;
	width:40px;
	border-radius:50%;
	background:red;
	transform:translateX(0);
	transition:transform .5s ease,opacity .2s ease;
	opacity:0;
}

4. .connect > div:nth-of-type(7n+1):hover ~ .counter:after{transform:translateX(36px);opacity:1;}
.connect > div:nth-of-type(7n+2):hover ~ .counter:after{transform:translateX(136px);opacity:1;}
.connect > div:nth-of-type(7n+3):hover ~ .counter:after{transform:translateX(236px);opacity:1;}
.connect > div:nth-of-type(7n+4):hover ~ .counter:after{transform:translateX(336px);opacity:1;}
.connect > div:nth-of-type(7n+5):hover ~ .counter:after{transform:translateX(436px);opacity:1;}
.connect > div:nth-of-type(7n+6):hover ~ .counter:after{transform:translateX(536px);opacity:1;}
.connect > div:nth-of-type(7n+7):hover ~ .counter:after{transform:translateX(636px);opacity:1;}
0 Likes

#7

No not on the demo you provided it won’t because its on the wrong axis. That’s why it pushes it to the right and not the bottom. Most times you can just use an auto margin on the side you want pushed to the edge of the container.

You didn’t really need to start again as it was basically working with the tweaks I mentioned :slight_smile:

i.e. You just needed this:

body {
	display: flex;
	justify-content: center;
	align-items: center;
	min-height: 100vh;
	background-color: #e6e6e6;
	flex-direction: column;
}

When you use flex-direction:column the axis is reversed and justify and align properties refer to the new axis.

I’ll try :slight_smile:

1. *, *:before, *:after {
	box-sizing: inherit;
}

That sets the border-box model so that padding margins and borders are kept inside the element and not added to its width (unlike the default model). It makes it easier to maintain when doing demos like this and indeed is the method I use for all designs these days.

Basically if you set a div to width:300px and add 2em padding and 5px borders the total size is still 300px.

More info here.

2. .connect > div:not(.counter):after {
	content:"";
	z-index:-1;
	position:absolute;
	left:0;
	right:0;
	top:-999em;
	bottom:-999em;
	background:transparent;
	transition: all 0.5s ease;
}

This uses the content property combined with the :after pseudo element. this allows us to create an element without using extra mark up. I could have used a div instead but why waste an element.

The :not property just excluded the properties in that rule being written into .counter as that is also a child div of .connect.

The above rule supplies the column hover colour by over-sizing the pseudo element so that it is much taller than the column (each div when hovered creates a box using the :after element that is taller than the whole column). The extra height is hidden with overflow:hidden on the parent to complete the effect.

3. .connect > div.counter:after {
	content:"";
	display:block;
	padding:0;
	position:absolute;
	z-index:100;
	top:0px;
	left:0;
	right:auto;
	height:40px;
	width:40px;
	border-radius:50%;
	background:red;
	transform:translateX(0);
	transition:transform .5s ease,opacity .2s ease;
	opacity:0;
}

Same method as the previous one except we create the counter with this one and position it at the top of the layout.

.connect > div:nth-of-type(7n+1):hover ~ .counter:after{transform:translateX(36px);opacity:1;}
.connect > div:nth-of-type(7n+2):hover ~ .counter:after{transform:translateX(136px);opacity:1;}
.connect > div:nth-of-type(7n+3):hover ~ .counter:after{transform:translateX(236px);opacity:1;}
.connect > div:nth-of-type(7n+4):hover ~ .counter:after{transform:translateX(336px);opacity:1;}
.connect > div:nth-of-type(7n+5):hover ~ .counter:after{transform:translateX(436px);opacity:1;}
.connect > div:nth-of-type(7n+6):hover ~ .counter:after{transform:translateX(536px);opacity:1;}
.connect > div:nth-of-type(7n+7):hover ~ .counter:after{transform:translateX(636px);opacity:1;}

This rule says that when you hover over any div then move the counter by xx px. .counter is a sibling so we can use the ~ rule to select .counter when it follows a previous div.

The nth-of-type allows the css to apply different measurements based on which div is being hovered. As we have 7 across then 7n+1 selects all the divs in the first column. 7n+2 selects all the divs in the second column and so on.

The nth-child generator here is a useful tool to play around with.

https://css-tricks.com/examples/nth-child-tester/

The layout itself is just a flexbox grid with no special features other than allowing the boxes to wrap as required.

2 Likes

#8

Thank you!!!

0 Likes

#9

Part 1

Hey @PaulOB So i took your connect four design and did a few things. 1. I changed .connect-outer to .board-wrapper, then changed .connect to .board. The next big thing I did was comment out certain properties in most of the rules that didn’t change the overall appearance or function of the board. These are my questions. Please take your time and look at the properties that are commented out and please give me an explanation that a novice could understand as to why you put them there and why they don’t need to be there for the game to function like your original design. I’ve spent hours looking at your CSS and really need a good explanation to how this stuff is working, thank you!:slight_smile:

part 2

this part is similar to part 1. I’m just asking some more detailed questions about the effect of certain properties. I might ask something you already answered in part 1. In that case just ignore the question.

a. At the top of my CSS I put a red border around everything. I do this to see my elements as I begin to start working with them. If you uncomment that code an apply the border to everything you can see it widens the board an extra column?

b. I also noticed if I remove the position:relative; on board > div every column is darkened when the cursor is hovered over?

c. .board > div:not(.counter):after changed to .board > div:after doesn’t do anything to .counter?

d. This really isn’t a question but you’ve probably seen div.counter: before. Which is the inner circle inside .counter:after. Just wanted to know if there was a better way to make this, especially the rules that move it along with .counter:after. I just copied what you did with .counter:after and did the same thing with .counter:before. I tried to connect the two to shorten up the code like this

.board > div:nth-of-type(7n+1):hover ~ .counter:after, .counter:before{transform:translateX(14px);opacity: 1;}

but that didn’t work

e. ok last question. I’m ready to drop the chip but I’m not sure how? In my original design I used an html element for the floating chip not a pseudo element. I know I could push .counter:after & .counter:before down with the top property, but then I’d have to generate a new chip. which I don’t know how to do cause there pseudo elements? And then How would I place the chip in that div or slot so the js knows where its at?(also is using the DOM for the game logic like that a good idea?) Please Paul take your time with these questions. I’m in no rush and would appreciate drawn out but simple answers. Thank you again! your such a big help:)

0 Likes

#10

Where is the code I am looking at? I didn’t see a red border in your first example.

Note that adding a 1px border will increase the size of the elements by 2px which means that they may no longer fit in the space allocated unless you have used the border-box model for everything which probably answers your question.

e.g. this is the box model I usually use.

html {
	box-sizing: border-box;
}
*, *:before, *:after {
	box-sizing: inherit;
}

Rather than using a border for testing use outline instead as that does not impact on layout and won’t break things whatever box model you choose.

Position:relative creates a positioning context for absolutely placed children. If you remove the position:relative then the absolute element will be placed in relation to the nearest ancestor that has a position defined. (If none exist then your absolute element ends up being placed from the root element (effectively the body).)

Therefore removing a position:relative that is being used as a positioning context for its children will result in breaking the intended display because the absolute elements gets placed in a different context to where it should have been.

I can’t see your code but the code above is basically saying don’t do anything to .counter. So if you are saying it doesn’t do anything to .counter then it is doing its job :slight_smile:

When you have a comma separated list of selectors they have nothing in common with each other apart from the property values you apply.

Therefore you need each rule to be a complete rule.
e.g.

.board > div:nth-of-type(7n+1):hover ~ .counter:after, 
.board > div:nth-of-type(7n+1):hover ~ .counter:before {transform:translateX(14px);opacity: 1;}

It’s just a comma separated list that share the property values. There is nothing inferred by being comma separated.

You don’t need to drop the chip at the top because you will actually require 42 counters (one for each space on the board). Your logic will need to decide which column is being hovered over and which space is available. You could then animate the counter into place. Imagine keeping all 42 counters above the board but hidden. When you click to drop you can drop the counter that matches the available square.

Of course there are a million other ways to do this and you could indeed create a new counter each time one counter is dropped into place but you would need to program this accordingly.

I have actually modified my original demo to allow a counter to drop into place just for proof of concept.

https://codepen.io/paulobrien/full/QPNXJg

It will also swap colours automatically and declare a winner.

My JS is basic so don’t copy any of my code as the JS forum is the best place to get logic and reliable code. Indeed the logic part is something that you need to work out for yourself so that you can build your code to achieving what you want to happen.

0 Likes