UI自动化

article/2025/10/24 12:38:32

UI自动化

  • 本地搭建Javall商城项目
  • maven环境搭建
    • Maven项目管理
    • Maven仓库
  • TestNG 单元测试框架
    • 安装testNG插件
  • 八大定位方式
  • 知识点
    • 隐式等待:
    • 显式等待:
    • iframe切换:
    • window切换:
    • Select下拉框
    • Radio Button(单选按钮)
    • Checkbox(复选框)
    • 时间组件
    • 断言:分别保存修改前和修改后的数据,然后断言 或 获取页面数据断言
    • alert弹框断言 - js弹框(开发者工具无法定位的就是js弹框,可以用开发者工具定位的弹框是模态框)
    • cookie绕过(手动登录获得cookie添加到代码中)
    • 鼠标悬浮
    • 拖拽
    • 文件上传

本地搭建Javall商城项目

安装mysql(用户名、密码设置)——安装navicat——navicat连接mysql(localhost、用户名 密码)——navicat创建数据库导入sql——部署tomcat(项目war包放在tomcat的webapps路径内修改项目的配置文件)——启动tomcat——打开本地地址

maven环境搭建

maven安装(下载、setting文件配置maven本地仓库目录和阿里云镜像仓库)——配置环境变量(maven_home、path)——验证maven安装成功——下载常用jar包(mvn help:system)——IDEA下载maven插件——eclipse/idea新建maven项目——pom文件添加依赖jar(selenium,下载失败时找到本地maven仓库删掉文件夹重新更新maven强制下载)——IDEA中设置maven——Idea配置JDK——安装浏览器驱动(chrome禁止升级、下载chromedriver驱动、配置driver环境变量建议默认位置)——检查chromedriver是否安装成功(cmd chromedriver)

Maven项目管理

Maven是项目管理工具。主要服务于基于Java平台的项目构建,依赖管理和项目信息管理。
使用Maven的好处:只需要定义一个pom.xml, 然后把源码放到默认的目录,Maven会管理依赖和构建过程

Maven仓库

Maven 本地仓库:settings.xml中配置的本地路径,存储下载的jar包
Maven 中央仓库:settings.xml中配置的镜像仓库(eg: 阿里云…)
Maven 私服:一种特殊的远程仓库,它架设在局域网内的仓库,通常作为公司的中央仓库

在这里插入图片描述

IDEA中设置maven:File—Settings——Build—Build Tools——Maven

Idea配置JDK:File—Project Structure——Project

如果chrome浏览器安装不是默认路径(C:\Program Files (x86)
\Google\Chrome\Application)的话,需要指定chrome所在的路径:

在这里插入图片描述

下载浏览器驱动(chromedriver)地址:http://chromedriver.storage.googleapis.com/index.html
将chromedriver配置到环境变量中,cmd窗口执行chromedriver有信息则配置成功

TestNG 单元测试框架

安装testNG插件

在线安装:file——settings——plugins——搜索插件名TestNG进行安装

在这里插入图片描述

手动安装:下载插件包——plugins页面选择install plugin from disk

在这里插入图片描述

下载插件后需要添加依赖jar包:
1、通过maven的pom文件添加依赖
2、手动添加依赖包(见下图):先建文件夹libs把jar包放入该文件夹,在按下图操作

在这里插入图片描述

常用注解如下
执行顺序:BeforeSuite
BeforeTest
BeforeClass
BeforeMethod
Test

@BeforeSuite: 标示此注解的方法会在当前测试集合(suite)中的任一测试用例开始运行之前执行。
@AfterSuite: 标示此注解的方法会在当前测试集合(suite)中的所有测试程序运行结束之后执行。
@BeforeTest:标示此注解的方法会在 Test 中任一测试用例开始运行前执行。
@AfterTest:标示此注解的方法会在 Test 中所有测试用例运行结束后执行。
@BeforeGroups: 标示此注解的方法会在分组测试用例的任一测试用例开始运行前执行。
@AfterGroups: 标示此注解的方法会在分组测试用例的所有测试用例运行结束后执行。
@BeforeClass: 标示此注解的方法会在当前测试类的任一测试用例开始运行前执行。
@AfterClass: 标示此注解的方法会在当前测试类的所有测试用例运行结束后执行。
@BeforeMethod: 标示此注解的方法会在每个测试方法开始运行前执行。
@AfterMethod:: 标示此注解的方法会在每个测试方法运行结束后执行。
@Test: 标示此注解的方法会被认为是一个测试方法,即一个测试用例

常用断言
assertTrue 判断是否为 true
assertFalse 判断是否为 false
assertEquals 判断是否相等,Object 类型的对象需要实现 hashCode 及 equals 方法
assertNotEquals 判断是否不相等
assertEqualsNoOrder 判断忽略顺序是否相等
assertSame 判断引用地址是否相同
assertNotSame 判断引用地址是否不相。
assertNull 判断是否为 null
assertNotNull 判断是否不为 null

测试集合
在自动化测试的执行过程中,通常会产生批量运行多个测试用例的需求,此需求称之为运行测试集合(TestSuite)。
通过 TestNG.xml 的配置,可批量运行测试用例

依赖测试
某些复杂的测试场景需要按照某个特定顺序执行测试用例,以此保证某个测试用例被执行之后才执行其它测试用例,此测试场景运行需求称之为依赖测试。
通过依赖测试,可在不同测试方法间共享数据和程序状态。
TestNG 支持依赖测试,使用 dependsOnMethods 及 dependsOnGroups 参数来实现。

用例顺序
使用参数 Priority 可实现按照特定顺序执行测试用例,1、2、3依次执行
Priority 是全局性参数,多个类中优先级相同的话容易乱,所以建议用测试用例名称排序不加Priority

数据驱动
Testng 提供了数据驱动模式,以 DataProvider 注解完成

八大定位方式

id 对应元素的id属性 By.id(“password”)

name 对应元素的name属性 By.name(“username”)

linktext 对应a表签 By.linkText(“登录”)

pertialLinkText 对应a表签,模糊匹配a表签的文本 By.partialLinkText(“登录”)

tagname

className 对应元素的class属性 By.className(“blue_btn”) class值有空格不行,可以取部分值

css selector
css:重叠样式表
绝对路径定位:html>body>footer>div ( 表签>表签)
相对路径定位: body nav (中间空格)
class属性定位:.container (.class值)
id定位: #username (#id值)
属性定位:div[role=‘dialog’][tabindex=‘-1’] 表签[属性1=‘属性值1’][属性2=‘属性值2’]

xpath
绝对路径定位:html/body/div/nav/div/div[2]/ul[2]/li[2] 不建议使用
相对路径定位://ul[@class=“nav navbar-nav user-menu navbar-right”]/li[2]
(//button)[2] ()表示定位的所以元素强制排序
//button[2] 表示同级元素的第二个
//button[text()=‘写消息’]
//*[text()=‘发送’]
(//button)[last()]

xpath轴定位:
ancestor 选取当前节点的所有先辈 //a[@id=“unread_messages”]/ancestor::ul ul是表签
ancestor-or-self 选取当前节点的所有先辈 以及当前节点本身
parent 选取当前节点父节点 //a[@id=“unread_messages”]/parent::li li是a表签的父表签
//a[@id=“unread_messages”]/… 功能与上相同
child 选取当前节点所有子元素 不常用 因为/就可以
descendant: 选取当前节点的所有后辈 //a[@id=“unread_messages”]/descendant:😗
descendant-or-self 选取当前节点的所有后辈 以及当前节点本身

following 选取文档中当前节点之后的所有节点 //div/following:😗
following-sibling 选取当前节点之后的所有同级节点
//div[@class=“wrap”]/following-sibling::footer

//[@text=“私信消息”]/…/following-sibling::[1]/*[1]
preceding 选取文档中当前节点之前的所有节点
preceding-sibling 选取当前节点之前的所有同级节点
//div[@class=“wrap”]/preceding-sibling::div[1] []内的数字倒叙排

包含 //input[contains(@type,“check”)]

元素定位不到原因
(1)页面响应太慢元素未出现,需要加等待时间
(2)元素被遮挡,页面最大化
(3)是否有iframe、新窗口打开
(4)确认元素定位是否正确

知识点

隐式等待:

  • 1、指定时间内不断查找元素,一旦找到元素不再等待,执行下行代码
  • 2、全局性的等待,仅仅对findElement方法有效 可以多次设置
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS)

有了隐式等待并不是说不需要Thread.sleep()了,因为隐式等待仅仅对findElement方法有效,很多操作类的方法例如输入后点击前需要等待或页面元素本身已经加载了只是看不到需要点击框才会有输入框还是需要Thread.sleep()
隐式等待对findElements方法不生效

显式等待:

1、显示等待是针对单一元素或一组元素进行智能等待
2、可以针对元素的操作进行显示等待
3、可以针对弹框进行显示等待
4、可以针对自定义代码进行显示等待

针对元素操作的显示等待

String username = new WebDriverWait(driver,10).until(new ExpectedCondition<String>() {@Overridepublic String apply( WebDriver webDriver) {return webDriver.findElement(By.xpath("//a[@class='dropdown-toggle']/span")).getText();}});

针对弹框的显示等待

Alert alert = new WebDriverWait(driver, 10).until(ExpectedConditions.alertIsPresent());//在指定超时时间内等待弹框出现//Alert alert = driver.switchTo().alert();
String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");

自定义代码的显示等待(一闪而过的提示信息也可用显示等待)

Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {@Overridepublic Boolean apply(WebDriver d) {return d.getPageSource().contains("sinRcosT");}});
//获取一闪而过的提示信息
Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {@Overridepublic Boolean apply(WebDriver d){return d.getPageSource().contains("个人资料修改成功");}});

失败截图,利用io包的FileUtils

org.apache.commons.io.FileUtils
File file=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File("images/loginerror.png"));
System.out.println("登录失败");
Assert.fail(e.getMessage());

iframe切换:

iframe相当于网页里套网页,iframe表签里又有html

在这里插入图片描述

遇到iframe里的元素,先将driver切换至iframe再定位
切换方式:
1、使用元素id;
2、使用元素name;
3、使用iframe索引即第几个iframe,使用//iframe查看;
4、使用元素对象

使用id/name:driver.switchTo().frame(“ptlogin_iframe”);
使用索引:driver.switchTo().frame(0);
使用iframe表签:WebElement iframe = driver.findElement(By.tagName(“iframe”));
driver.switchTo().frame(iframe);

返回默认: driver.switchTo().defaultContent();
返回上一级: driver.switchTo().parentFrame()
检查当前页是否有iframe://iframe

window切换:

遇到元素在新打开的窗口时,先将driver切换至window再定位
1、先获取当前的windowhandle
2、操作打开新界面后,获取所有的windowhandles
3、遍历windowhandles,判断和当前的windowhandle不一样则切换windowhandle

String windowHandle1 = driver.getWindowHandle();
driver.findElement(By.linkText("Selenium3环境搭建")).click();Set<String> windowHandles = driver.getWindowHandles();
for(String s : windowHandles){if(!windowHandle1.equals(s)){driver.switchTo().window(s);break;}
}

多个window时可以获取每个window的title,然后遍历所有的window根据title切换window

driver.get("http://ask.testfan.cn/");
driver.manage().window().maximize();
String windowHandle1 = driver.getWindowHandle();driver.findElement(By.linkText("Selenium3环境搭建")).click();
driver.findElement(By.linkText("如何用appium设置设备的网络状态")).click();Set<String> windowHandles = driver.getWindowHandles();
for(String s : windowHandles){driver.switchTo().window(s);String title = driver.getTitle();if(title.equals("Selenium3环境搭建")){driver.switchTo().window(s);break;}
}

根据url切换window

for(String s:windowHandles) {driver.switchTo().window(s);String url =driver.getCurrentUrl();//获取当前界面的urlif(url.equals("http://ask.testfan.cn/article/556")) {break;}}

Select下拉框

下拉框进行操作时首先要定位到下拉框, 再进行操作:
• Select select=new Select(driver.findElement(By.id(“XXX”)))
选择对应的选项
• select.selectByVisibleText(String) 通过页面可见文本去选择
• select.selectByValue(String) 通过html中的value值去选择
• Select.selectByIndex(Int) 通过index来选择,从0开始

WebElement province = driver.findElement(By.id("province"));Select select = new Select(province);select.selectByVisibleText("浙江");   //通过肉眼看到的下拉选项文字选择
// select.selectByIndex(2);       //通过下拉选项索引选择
// select.selectByValue("3");    //通过下拉选项的value值选择
// select.getFirstSelectedOption().getText();  //当前选择的值

Radio Button(单选按钮)

单选按钮和多选按钮都当做普通button处理即可,找到radio button或者checkbox以
后,可以通过如下方法进行操作:
• Button.click() 点击单选或者复选框
• Button.clear() 清空选项

//修改性别,哪个没被选中选哪个
List<WebElement> genders = driver.findElements(By.name("gender"));
String sexValue = "";
for(WebElement we : genders){if(!we.isSelected()){we.click();sexValue=we.getAttribute("value");   //获取元素的属性  期望值break;}
}
List<WebElement> genders = driver.findElements(By.xpath("//label[@class=radio-inline]"));
for(WebElement we : genders){if(!we.isSelected()){we.click();break;}
}

Checkbox(复选框)

时间组件

借助js修改日期

//修改生日
JavascriptExecutor js = (JavascriptExecutor)driver;  //js执行器
js.executeScript("document.getElementById('birthday').value='1987-05-17'");

获取元素值的js:document.getElementById(“birthday”).value
修改元素值的js:document.getElementById(“birthday”).value=“1989-09-26”

断言:分别保存修改前和修改后的数据,然后断言 或 获取页面数据断言

单选框断言

//修改性别,哪个没被选中选哪个
List<WebElement> genders = driver.findElements(By.name("gender"));
String sexValue = "";
for(WebElement we : genders){if(!we.isSelected()){we.click();sexValue=we.getAttribute("value");   //获取元素的属性  期望值break;}
}
点击提交信息后
//获取性别实际值
List<WebElement> genders1 = driver.findElements(By.name("gender"));
String sexActualValue = "";
for(WebElement we : genders1){if(we.isSelected()){sexActualValue=we.getAttribute("value");   //实际值break;}
}

日期框断言

//修改生日
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("document.getElementById('birthday').value='1987-05-17'");
String birthday = driver.findElement(By.id("birthday")).getAttribute("value");  
//获取生日实际值
String birthdayActual = driver.findElement(By.id("birthday")).getAttribute("value");  //实际值

下拉框断言

 //修改省份WebElement province = driver.findElement(By.id("province"));Select select = new Select(province);select.selectByVisibleText("浙江");   //通过肉眼看到的下拉选项文字选择String text = select.getFirstSelectedOption().getText();      //期望值// select.selectByIndex(2);       //通过下拉选项索引选择
// select.selectByValue("3");    //通过下拉选项的value值选择//获取省份实际值
WebElement province1 = driver.findElement(By.id("province"));
Select select1 = new Select(province1);
String text1 = select1.getFirstSelectedOption().getText();      //实际值
Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {@Overridepublic Boolean apply(WebDriver d) {return d.getPageSource().contains("保存会员成功");}});

用例失败保存截图

}catch (Exception | Error e){File file = ((TakesScreenshot)(driver)).getScreenshotAs(OutputType.FILE);try {FileUtils.copyFile(file,new File("images/loginerror.png"));} catch (IOException e1) {e1.printStackTrace();}Assert.fail(e.getMessage());
}

alert弹框断言 - js弹框(开发者工具无法定位的就是js弹框,可以用开发者工具定位的弹框是模态框)

弹框不关掉无法截图

Alert alert = driver.switchTo().alert();
String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");
//  alert.accept();      //确定弹框,弹框关闭
//  alert.dismiss();     //取消弹框,弹框关闭//如果弹框出现的慢直接切换至弹框就会有问题,因此需要显示等待
Alert alert = new WebDriverWait(driver, 10).until(ExpectedConditions.alertIsPresent());//在指定超时时间内等待弹框出现String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");

cookie绕过(手动登录获得cookie添加到代码中)

driver.get("http://localhost:8080/javamall/admin/backendUi!main.do");
driver.manage().window().maximize();
driver.manage().deleteAllCookies();  //删除所有的cookie
Cookie cookie = new Cookie("JSESSIONID","36C07DFAB78EAD8771A550BE2FAFF754");
driver.manage().addCookie(cookie);
driver.get("http://localhost:8080/javamall/admin/backendUi!main.do");

鼠标悬浮

WebElement memMenu = driver.findElement(By.xpath("//*[text()='会员']/../.."));
Actions actions = new Actions(driver);
actions.moveToElement(memMenu).perform();
driver.findElement(By.linkText("会员列表")).click();

拖拽

拖拽的元素不在页面出现时可先点击屏幕下方的某个元素再进行拖拽或发送TAB键滑动页面

actions.sendKeys(Keys.TAB).perform();

通过元素进行拖拽

WebElement iterm1 = driver.findElement(By.xpath("//li[text()='Item 1']"));
WebElement iterm2 = driver.findElement(By.xpath("//li[text()='Item 2']"));
Actions actions = new Actions(driver);
actions.dragAndDrop(iterm1,iterm2).perform();

X轴从左到右变大,Y轴从上到下变大

WebElement iterm1 = driver.findElement(By.xpath("//li[text()='Item 1']"));
Actions actions = new Actions(driver);
actions.dragAndDropBy(iterm1,0,50).perform();//向下拖50像素

文件上传

//将图片路径放到粘贴板
StringSelection file=new StringSelection("C:\\Users\\Public\\Pictures\\Sample Pictures\\沙漠.jpg");  //将路径转换成字符串的格式
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(file, null);Robot robot=new Robot();
//按下ctrl+v
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
//释放ctrl+v
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_V);
//按下回车并释放
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);

http://chatgpt.dhexx.cn/article/ULeojdhP.shtml

相关文章

UI自动化平台(一)

前言&#xff1a;最近萌生了做UI自动化平台的想法&#xff0c;以前做UI自动化都是直接脚本化的&#xff0c;也一直觉得UI改动一般都是很频繁&#xff0c;所以慢慢的脚本化的工作都放弃了&#xff0c;但是目前在公司&#xff0c;发现还是有点用的&#xff0c;公司的前辈也一直在…

ui自动化设计思路

小伙伴让我周末做技术分享&#xff0c;想着这是一件有意义的事情&#xff0c;便答应了下来&#xff0c;那就给大家讲讲ui自动化吧。这里会结合具体的代码给大家讲ui自动化一些理念&#xff0c;方案设计。 本文将探讨ui自动化设计思路&#xff0c;主要围绕以下方面展开讲解&…

使用UI Automation库用于UI自动化测试

&#x1f4cc; 博客主页&#xff1a; 程序员二黑 &#x1f4cc; 专注于软件测试领域相关技术实践和思考&#xff0c;持续分享自动化软件测试开发干货知识&#xff01; &#x1f4cc; 公号同名&#xff0c;欢迎加入我的测试交流群&#xff0c;我们一起交流学习&#xff01; UI A…

你知道什么叫三目表达式吗

目录 什么是三目表达式&#xff1f; 运用 1.单个使用 2.嵌套使用 什么是三目表达式&#xff1f; 1.三目表达式是一种编程中常见的表达式,它能够有效地帮助我们解决一些问题。 2.三目表达式由三个部分组成,分别是:条件表达式、结果表达式 听不懂么&#xff0c;那我们就来举个…

使用UI Automation实现自动化测试 --工具使用

当前项目进行三个多月了&#xff0c;好久也没有写日志了&#xff1b;空下点时间&#xff0c;补写下N久没写的日志 介绍下两个工具 我本人正常使用的UISpy.exe工具和inspect.exe工具 这是UISPY工具使用的图&#xff0c;正常使用到的几个属性 这里重点说一下微软件的UI Autom…

自动化测试平台(十):UI自动化元素页面的管理功能实现

一、前言 上一章我们完成了列表组件公共化封装和项目管理功能的实现,这一章将实现UI元素及元素页面的管理功能,换句话说就是对selenium执行定位操作的元素进行管理。 完整教程地址:《从0搭建自动化测试平台》 项目在线演示地址:http://121.43.43.59/ (帐号:admin 密码…

Android自动化测试入门(二)UI Automator

UI Automator是一个界面测试框架&#xff0c;支持跨进程&#xff0c;几乎可以模拟所有的人工操作。需要运行在4.3或者更高的系统版本上。它的测试代码的编写不依赖于目标应用的内部实现细节&#xff0c;非常适用编写黑盒自动化测试。 UI Automator 测试框架的主要功能包括&…

03-vue基础-插值表达式

文章目录 vue插值表达式vue通过data提供数据通过插值表达式显示数据安装vue开发者工具总结 vue插值表达式 本文要讲解的内容如下&#xff1a; 通过data提供数据通过插值表达式显示数据vue开发者工具的安装与使用 vue通过data提供数据 vue中通过template可以提供模板&#xf…

接口自动化和UI自动化:定义、区别及示例代码

目录 1.接口自动化 2.UI自动化 3.接口自动化和UI自动化的区别 4.结论 5.总结 在软件测试领域中&#xff0c;接口自动化和UI自动化是两个常见的测试类型&#xff0c;它们分别用于测试应用程序的不同层面。本文将介绍接口自动化和UI自动化的基本定义、区别以及示例代码。 1…

autojs,ui,界面学习,以及定时脚本页面的构建

注释掉ui或者ui的报错 再来就是认识几个单词&#xff0c;gravity 重力 简单来说就是你所创造的东西你想要它所处的位置在什么地方&#xff1a; left 靠左right 靠右top 靠顶部bottom 靠底部center 居中center_vertical 垂直居中center_horizontal 水平居中 text的一些属性&…

UI自动化测试03

一、警告框处理 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>警告窗口操作</title><script type"text/javascript">// JavaScript一些函数// 定义了一个函数function alterbutton(){alert("…

【UI自动化-3】UI自动化元素操作专题

前言 在熟悉了元素定位之后&#xff0c;我们接下来就要学习对定位到的元素进行操作这项内容了。我简要做了个总结&#xff0c;如下图&#xff1a; 1 基本操作 元素的基本操作有很多&#xff0c;常用的有三个&#xff1a;click&#xff08;点击&#xff09;、clear&#xff…

mysql数据库命令备份还原

一、备份指定表&#xff1a; 在安装有mysql客户端的服务器命令行执行&#xff1a; mysqldump -h mysqlip -uusername -ppassword dbname tablename1 tablename2 > /home/XXXX.sql 如果表特别大&#xff0c;可以加入“nohup &” 来后台执行&#xff0c;以防窗口关闭等…

cmd 下mysql常用的数据库命令

其实如果不想打开mysql软件去操作数据库的话&#xff0c;可以通过DOS命令去操作数据库&#xff0c;也是比较快捷的方式&#xff0c;根据个人的操作喜好而定。 按 winR 键后输入 cmd 进入DOS命令窗口 切换目录到mysql文件下的bin目录&#xff0c;这里以phpstudy_pro 集成环境为…

oracle创建数据库命令

oracle创建数据库命令 1.打开cmd 连接系统默认数据库 2. 创建表空间 CREATE TABLESPACE DATA DATAFILE ‘D:\oracle\DATA\DATA.ORA’ size 10G autoextend on next 1M Maxsize unlimited logging extent management local segment space management auto; 3.创建临时空间 CRE…

css grid 自动高度_十一款游戏教你学会 CSS!

关注“脚本之家”&#xff0c;与百万开发者在一起 网上有很多有助于学习CSS的游戏&#xff0c;本文收集了一些非常实用的免费CSS游戏&#xff0c;希望这些游戏可以帮助你再次体验CSS的乐趣&#xff01; 作者 | Andreas Mller 译者 | 弯月&#xff0c;责编 | 郭芮 出品 | CSDN(I…

CSS设置高度等于动态的宽度

如果子元素根据父元素设置宽度&#xff0c;那么将其高度设置为0&#xff0c;并将padding-bottom设置为百分比&#xff0c;则该子元素的高度将根据它的宽度计算。 <div class"div1"><div class"div2"></div> </div>.div1{width:40…

通关这8个游戏,保证你能精通CSS

在知乎上随便一艘,CSS难学,就会找到很多关于CSS为什么这么难学的提问?各种回答都有,但是我觉得在游戏中学习CSS是最好的,毕竟人的天性就是爱玩。以以 Flexbox 布局为例。弹性容器的属性justify-content可以有12 个不同的值,我们要怎么记住呢?在Flexbox Froggy这款游戏就…

Web前端--HTML+CSS+JavaScript酷炫游戏动漫网页设计

临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大&#xff1f;网页要求的总数量太多&#xff1f;HTML网页作业无从下手&#xff1f;没有合适的模板&#xff1f;等等一系列问题。你想要解决的问题&#xff0c;在这里常见网页设计作业题材有 个人、 美食、 公司、…

css 真正意义上达到height:100%,自适应屏幕高度

最近发现了个用绝对布局写自适应屏幕的写法&#xff0c;让我觉得&#xff0c;之前小程序傻傻读屏幕高再给背景view赋值min-height的写法简直太傻了毕竟能用css解决的问题最好就不要js .shi{position: absolute;top: 0px;bottom: 0;left: 0;width: 20%;background-color: black…