`
hax
  • 浏览: 962448 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

面向未来的CSS实践

阅读更多
本文源于http://ued.taobao.com/blog/2007/08/12/css-notes/的讨论。淘宝UED团队的小马对taobao的CSS编程原则描述如下:
小马 写道
* 尽量不使用hack
* 尽量不使用ie6不支持的选择符
能符合这两个条件的最简洁的写法,就是我们的目标。


由此展开,我论述了在CSS实践上的另一种思路。这是我自去年年中至今年4月在SNDA进行商城开发过程中对于前端web设计编程的思考和实践的首次书面整理。

如下:

对于taobao网站css的原则,我个人认为这两条原则是较为保守的,当然对于taobao这样的网站,采用比较保守的策略是很合情合理的。

我谈一下我对着两个原则的一般看法。

对于hack,我觉得要区别对待。对于使用selector或利用其他特定浏览器的bug来做hack的,需要谨慎。因为这类hack没有向后兼容性,很可能碰到下个版本的浏览器,支持了原先不支持的selector,或者修复了原先的bug,这就惨了。MSIE7就是一个典型例子。实际上90%的hack都是为IE准备的,而对于IE来说,最好用condition comments,这是IE团队推荐的方法 —— 它的优点除了向后兼容性的保证之外,还有就是可以把IE特定的代码写在单独的stylesheet里(其他浏览器可以不load它从而节约带宽),但是缺点也是这个,就是同一个效果,要在两个样式表里维护。

对于第二条原则,即不使用IE6不支持的selector,我觉得对多数网站来说,就过于保守。

我推崇一种面向未来的CSS实践。即大胆采用CSS2.1甚至部分CSS3的特性。因为绝大多数特性,Firefox、Opera、Safari等都已经很好的支持了。MSIE7也改进了许多,将来IE也无疑终究会完全支持CSS2.1。对于目前的IE,除了graceful degradation的方式(实际上整个内容样式分离的原则和良好的CSS设计可以确保这点,比如淘宝以前的“裸体”所体现的),可以考虑通过特定手段来patch之。

在这点上,我必须说,我原来也是一直坚持只用ie6的selector的。是什么改变了我?就是Dean Edwards的IE7!它的出现不仅在于实践价值——即提供了一个对于IE的补丁,让开发者可以直接写CSS2甚至CSS3。对我来说,它更是观念上的革新,原来事情可以这样做!

所以,尽管DE的IE7在大型商业网站上还是存在一些问题的(主要是Ajax下的样式刷新带来的性能问题),但是它启发了我们可以从另一个角度来思考CSS的运用。

比如说,从实践的角度出发,所有IE6不支持的各种CSS selector中,最不可缺少的是什么?

由我个人的经验来看,最有用的就是多class。其次是一些伪类。

一个最常见的例子是,当button获得focus的时候,我们希望改变它的样式。

CSS2.1下可以:
input[type=button] {…}
input[type=button]:focus {…}

对于IE,我们可以给input加一个class来表明它是button,我们也可以通过脚本来给当前focus的元素增加一个pc-focus类(pc前缀表示伪类)。但是同时有button和focus怎么办涅?IE不支持多class,意味着,你不能这样写:

input.button {…}
input.button.pc-focus {…}

IE会把上述代码错误的解释为:

input.button {…}
input.pc-focus {…}

结果你为button准备的focus效果可能会跑到其他input上,例如radiobox、checkbox上。

所以通常会看到有人会给出两个class一个是button,一个是button_focus,onfocus的时候,把button替换成button_focus。

input.button {…}
input.button_focus {…}

当然它可以工作,对于一向只用一个class的人来说,甚至可以用不太严谨的方式,在onfocus的时候className += '_focus',在onblur的时候className.replace('_focus', ''),这段代码可以通用,而不必为button写一遍,又为radio或者checkbox再写一遍。但是总的来说,这恐怕不是一个好方法。例如button_focus不能复用button的样式特性。如果你要复用,必须写成:

input.button, input.button_focus {…}
input.button_focus {…}

每一处类似的情况都要记住这个写法(且两句顺序不能颠倒)。
特别讨厌的是,即使在另一个地方,你不想要focus效果,因此只需要input.button,而不需要input.button_focus,但你也要记得第一句的写法,否则一旦有了焦点,input.button样式就失效了!

那么我们可以考虑另一种方式,即不是把button替换成button_focus,而是两个并存,onfocus的时候addClass('button_focus'),onblur的时候removeClass('button_focus')。写CSS的时候要注意优先级一致和顺序问题:必须保持.button_focus的样式声明在.button之后。

对于input的其他情况,也照例:

input.radio {…}
input.radio_focus {…}

onfocus的时候addClass('radio_focus'),onblur的时候removeClass('radio_focus')。

一般来说,在IE里我们就到此为之了。注意,对于一个元素的class属性里包含更多class例如3个或者4个class的情况,要用这种方式是非常麻烦的。因此遵循小马所说原则的开发者会尽量避免使用多class。

多个class能够让我们以正交的方式处理问题,而避免多class,实际上是强迫我们尽量把问题平面化,降低了我们对于设计的表达能力。而在实际需求的逼迫下,开发者往往会不得不作出一些作为特例的代码(例如上面的button到button_focus的替换法)。在团队开发中,假如团队缺乏一些处理这类问题的通用“模式”的话,结果会更麻烦。

总之,避免多个class的selector,就是一种典型的实现工具对设计方法的不合理约束,对于设计的简单性、可维护性、可复用性都可能造成伤害。

我们能否换一种思路思考呢?

我们不是削足适履,仅仅在没办法的时候才用一些特别代码来达到本质上可以用多个class的selector来表达的效果。而是确认,多个class的selector是我们的基本需求。问题就变成了,怎样让IE也支持多个class。

让我们回顾在前面的若干个focus/blur事件处理函数,本质是相同的。我们能否避免写那么多本质相同但可能很复杂的focus/blur处理函数?这是可行的,例如对于一个class属性包含若干个class的情况,你可以给所有的class X都add一份对应的X_focus。比方说,A[class='x y']如果获得focus,那就可以改为A[class='x y x_focus y_focus']。这个事件处理函数是通用的,也就是不管是什么元素,只要获得焦点,我就根据该元素所具有的class进行变换。好,既然我们可以捕捉到既是x又获得focus的A,我们为什么不能捕捉一个既是x又是y的A呢(A.x.y)。我们可以改成A[class='x y x_y x_focus y_focus']。

这里我们要迈出重要一步。获得focus本身,其实可以看作增加了一个focus伪类(记做pc-focus),所以A[class='x y']获得focus,就得到A[class='x y pc-focus'],按照我们前面的变换,并把既是x又是y并且获得focus的情况(A.x.y:focus)也考虑进来,最后我们可以得到:
A[class='
  x
  y
  pc-focus
  x_y
  x_pc-focus
  y_pc-focus
  x_y_pc-focus
']

如果我们推而广之,就能发现这其实就是在IE下模拟多类的效果。对于任何一个class='a b c d…'的情况,我们只要把class的值改为a b c d … a_b a_c a_d … b_c b_d … c_d … a_b_c a_b_d … a_c_d … a_b_c_d,然后在写css的时候遵循一定的规则:
多个class按照字母顺序书写,即把X.a.b.c, X.a.c.b, X.c.b.a统一写做X.a_b_c
按照优先级顺序书写,即先写X.a然后写X.a_b和X.c_d,最后写X.a_b_c_d;
就可以了。

实际上,我正在酝酿一个开源项目,遵循这个思路,并把所有这些变换自动化(通过htc来override className属性,能把class的转换自动化;自动产生focus,hover,first-child等伪类;通过css解析处理工具,能把CSS2.1的多class selector自动转换为等价的IE形式)。这样,开发者就可以自由一点的写CSS,而不必束手束脚了。相比较Dean Edwards的IE7,这种方法所提供的改进有限,并不能给予开发者完整的CSS2/3的支持,但是边际效用很大,更轻量级。因为本质上是使用IE自己的引擎,而不是自己实现的CSS Parser,所以对Ajax应用是透明的,在实际应用中性能也几乎没有损失。因此这一方案应能适用于大型商业网站。

虽然我的项目尚处于计划阶段,但是原理是很简单的,任何人都可以付诸实践。
分享到:
评论
9 楼 protti 2007-10-26  
有的时候  麻烦的是老项目  而不是新项目  

维护的时候受到的约束最多了
8 楼 hax 2007-08-16  
birdjavaeye 写道
相当不错,鼓励鼓励!

是否能让for IE的部分由IEPatch自动生成呢?


这正是目标之一。不过最近还没有时间开展项目。
7 楼 birdjavaeye 2007-08-16  
相当不错,鼓励鼓励!

是否能让for IE的部分由IEPatch自动生成呢?
6 楼 hax 2007-08-15  
被评为精华帖了,所以把原文又润色了一下,现在应该更容易理解了。

另附上在淘宝UED blog上的comments更新部分:

问题是怎么理解“复杂化”。实际上,更好的CSS支持必然能让事情变得更合理、简单、清晰、可维护。我之前对于table布局的讨论,对于多class selector在实际中运用的讨论,其实都说明了这一点。

那么什么让CSS变复杂了?其实正是那许多trick。我仍旧是拿段王爷的这个分隔线的例子。请比较我提出的方法和(稍作变形的)段王爷的方法:

ul { padding:0; margin:0; }
li { display:inline; }
li ~ li:before { content:url(sep.bmp); }

vs

ul { padding:0; margin:0; overflow:hidden; zoom:1; }
li {
display:inline;
background:url(sep.bmp) left center no-repeat;
zoom:1;
margin-left:-8px;
padding:0 8px;
}

sep.bmp是一个8px宽的图片。两段代码效果上是几乎等价的。并且对代码做了最大简化,去除了所有无关代码。

很容易看出哪个更简单。这种简单,不仅在于代码的量的多少,而且更关键的是在于对于意图的表述。前者很清晰。后者就算一个css老手,也得花点精神才看的出来。而且后者带有一些意图之外的副作用,例如获得了hasLayout,又如对background, padding和margin的征用。请注意,这还是一个我们都认为很合用,也蛮清晰的trick。如果是更复杂的trick呢?

当我们有大量样式的时候,css trick的累加所造成的可维护性的下降,是很可观的。这是“意图丢失”所造成的。当然良好的注释可以改善一下这个状况。

所以,请考虑一下意图清晰的CSS2.1代码所带来的好处。

然后我们考虑前者如何运用到IE中。
第一个方法,不管IE,在IE下自然graceful degradation。
第二个方法,用Dean Edwards的IE7或类似项目。
第三个方法,也是按照我计划项目(暂时称作IEPatch)的思路下的做法(虽然目前还是设想,但绝对可以实现):

ul { padding:0; margin:0; }
li { display:inline; }
/*因为暂时不能模拟sibling selector,所以换用了一种写法*/
li::before { content:url(sep.bmp); }
li:first-child::before { content:'’; }

/* for IE */
li { pe-before:enabled; }
li .pe-before { content:url(sep.bmp); }
li.pc-first-child .pe-before { content:''; }

设想中的IEPatch会使用一个htc重载className,元素会自动获得一些伪类,例如pc-first-child等价于:first- child伪类。同时,实现content属性,并通过一个扩展的pe-before属性来表示是否为一个元素产生::before伪元素。注意,这听上去很困难,但实际上确实是可以实现,而且不会对呈现性能造成影响的。

这样,上述的三行代码就表示:对于li启用::before伪元素,li的::before伪元素使用sep.bmp作为其内容,li如果是first-child则::before伪元素内容置空。

看上去for IE的部分似乎复杂了,但是其实并不复杂,因为它与前面的标准CSS代码是一一对应的(除了用作辅助的第一句)。

表示意图的代码,始终只有一份,就是以标准CSS书写的那份。for IE部分,只是遵循规则就可以得到的简单的转换,而不是复杂的trick。如果有工具帮助,更是很容易自动产生的(实际上可以纳入到整个项目的building流程中)。

这是我对于“复杂性”的理解。

CSS实践之所以复杂,绝大多数时候来自于trick。也正是trick,导致CSS实践有时候甚至变成了近乎于艺术的工作。然而,发现一个 trick所获得的快感其实是一种慢性毒药,因为CSS本身不该是这样的。它不应该让我们被迫带着枷锁跳舞,它应该易于使用,很好的反映我的设计意图。
5 楼 i_love_sc 2007-08-15  
我很感兴趣。希望快点看到楼主的劳动成果啊。
4 楼 hax 2007-08-15  
默认上支持最多3个class,也就是在CSS中可以写:
X.a.b.c,但是不支持X.a.b.c.d。对class属性里的个数没有限制(当然越多性能越差,但是没有css上class个数的影响大)。

也可以改变默认设置到4个、5个甚至更多,但是性能会有所下降。我测试下来,在目前的中低端机器上,8个以上就不太可以接受了。

但是实践当中,css中多class,一般都是2个或者3个,很少人会用到更多。所以这个方法在实践中是有效的。
3 楼 hax 2007-08-15  
一个雏形实现(以下代码以LGPL条款发布):
class.htc
<public:component lightweight="true">
<public:property name="className" get="getClass" put="setClass"/>
<public:method name="hasClass"/>
<public:method name="addClass"/>
<public:method name="removeClass"/>
</public:component>
<script>
if ('nodeType' in element) {
	MultiClassPatch.setClass(element, element.getAttributeNode('class').value);
}
function hasClass(name) {
	return MultiClassPatch.hasClass(element, name);
}
function getClass() {
	return MultiClassPatch.getClass(element);
}
function setClass(name) {
	return MultiClassPatch.setClass(element, name);
}
function addClass(name) {
	return MultiClassPatch.addClass(element, name);
}
function removeClass(name) {
	return MultiClassPatch.removeClass(element, name);
}
</script>


class.js
var MultiClassPatch = (function ()  {

	var MULTICLASS_MAX = 3;

	function getClass(e) {
		return e.getAttributeNode('class').value.
			replace(/\S*?[.]\S*/g, '');
	}

	function setClass(e, value) {
		log.trace('entry setClass: $1 $2', nodeInfo(e), value);
		
		var values = value.replace(/\S*?[.]\S*/g, '').split(/\s+/);
		var a = [];
		for (var i = 0, size = values.length, cache = {}; i < size; i++) {
			var v = values[i];
			if (!cache.hasOwnProperty(v)) {
				a.push(v);
				cache[v] = true;
			}
		}
		if (a.length > 8 /*avoid javaeye bug*/ ) {
			log.warn('Performance Warning: Too many ($1) class values.', a.length);
		}
		
		var mc = [];
		var s = a.join(' ');
		mc.push(s);
		
		names = a;
		
		var n = names.length < MULTICLASS_MAX ? names.length : MULTICLASS_MAX;
		while(n > 1) {
			n--;
			var a = [];
			for (var i = 0; i < names.length; i++) {
				var name = names[i];
				var hasName = new RegExp('(?:^|\\s+)(?:\\S*[.])?(?:' + escapeRegExp(name) + ')(?:[.]\\S*)?(?=\\s+|$)', 'g');
				a.push(s.replace(hasName, '').replace(/\S+/g, name.replace('$', '$$') + '.$&'));
			}
			s = a.join(' ');
			mc.push(s);
		}
		
		var v = mc.join(' ');
		e.getAttributeNode('class').value = v;
		
		log.trace('exit setClass');
	}

	function hasClass(e, value) {
		var re = new RegExp('(?:^|\\s)' + escapeRegExp(value.replace(/\s+/g, '.')) + '(?:\\s|$)');
		return re.test(e.getAttributeNode('class').value);
	}

	function addClass(e, value) {
		if (hasClass(e, value)) return false;
		setClass(e, getClass(e) + ' ' + value);
		return true;
	}

	function removeClass(e, name) {
		var hasName = new RegExp('(?:^|\\s+)(?:\\S*[.])?(?:' + escapeRegExp(name) + ')(?:[.]\\S*)?(?=\\s+|$)', 'g');
		var attr = e.getAttributeNode('class');
		attr.value = attr.value.replace(hasName, '');
	}

	function escapeRegExp(s) {
		return s.replace(/[(){}.*+?^$|\[\]\\]/g, '\\$&');
	}

	return {
		getClass:getClass,
		setClass:setClass,
		hasClass:hasClass,
		addClass:addClass,
		removeClass:removeClass,
		VERSION:'2.0'
	};
	
})();




测试代码:

<html>
<head>
<script src="../src/scripts/lang.js"></script>
<script src="../src/scripts/system.js"></script>
<script src="../src/scripts/log.js"></script>
<script src="../src/class.js"></script>

<style id="ie-class-patch">
* html body, * html body * { behavior:url(../src/class.htc); }
</style>

<style>
body { color:white; background:gray; }
.a { background:navy }
.b { background:maroon; }
.c { border:thin dotted; }
html>body  .a.b { background:green; }
* html     .a\.b { background:green; }
html>body  .a.b.c { border-width:medium; }
* html     .a\.b\.c { border-width:medium; }
html>body  .c.d.e { color:yellow; }
* html     .c\.d\.e { color:yellow; }
</style>
</head>
<body>
	<p class="a">a  background:navy</p>
	<p class="b">b  background:maroon</p>
	<p class="c">c  border:thin dotted</p>
	<p class="a b">a b  background:green</p>
	<p class="a b c">a b c  background:green; border:medium dotted</p>
	<p class="a b c d">a b c d  background:green; border:medium dotted</p>
	<p class="a b c d e">a b c d e  background:green; border:medium dotted; color:yellow</p>
	<p class="
		test-multiple-class-01 test-multiple-class-02 test-multiple-class-03
		test-multiple-class-04 test-multiple-class-05
	">multiple class 5</p>
	<p class="
		test-multiple-class-01 test-multiple-class-02 test-multiple-class-03
		test-multiple-class-04 test-multiple-class-05 test-multiple-class-06
	">multiple class 6</p>
	<p class="
		test-multiple-class-01 test-multiple-class-02 test-multiple-class-03
		test-multiple-class-04 test-multiple-class-05 test-multiple-class-06
		test-multiple-class-07
	">multiple class 7</p>
	<p class="
		test-multiple-class-01 test-multiple-class-02 test-multiple-class-03
		test-multiple-class-04 test-multiple-class-05 test-multiple-class-06
		test-multiple-class-07 test-multiple-class-08
	">multiple class 8</p>
	
	<p class="
		test-multiple-class-01 test-multiple-class-02 test-multiple-class-03
		test-multiple-class-04 test-multiple-class-05 test-multiple-class-06
		test-multiple-class-07 test-multiple-class-08 test-multiple-class-09
		test-multiple-class-10 test-multiple-class-11 test-multiple-class-12
		test-multiple-class-13 test-multiple-class-14 test-multiple-class-15
	">multiple class 15</p>
</body>
</html>


注意,这里没有包括所有代码,但是包括了关键的概念和实现方法。
2 楼 hax 2007-08-15  
性能是一个关键问题。因此我不会做任何dom循环,也不会用任何js selector。而是使用IE本身的能力。

实现上,最核心的一点就是override className。
1 楼 radar 2007-08-15  
我宁愿通过javascript来hack css.
毕竟现在 javascript sector很多,性能\提升都很好.


如果用你的htc方案,整个dom树循环可能避免不了吧?

相关推荐

    (完整版)《HTML5+CSS3网站设计基础教程》_教学大纲.pdf

    《HTML5+CSS3 网站设计基础教程》是面向计算机相关专业的一门专业基础课,涉及网页基础、HTML标记、CSS样式、网页布局、变形与动画等内容。本课程旨在让学生了解网页开发历程 及其未来方向,熟悉网页设计流程、掌握...

    HTML5+CSS3网页设计与制作—教学大纲.pdf

    **《HTML5+CSS3网页设计与制作》**作为一门面向计算机及相关专业的专业基础课程,旨在帮助学生掌握现代网页设计的核心技术。通过本课程的学习,学生不仅能深入了解网页的发展历程及其未来趋势,还能熟悉网页设计的全...

    The Book of CSS3禅意花园出品

    《CSS3禅意花园出品》一书由Peter Gasston撰写,是面向开发者的未来网页设计指南,详尽地介绍了CSS3这一革命性技术的核心概念、最新特性及其在现代网页设计中的应用。本书作为一本权威的技术手册,深入浅出地解析了...

    CSS网站布局实录 (第二版)PDF版

    1.7 面向现在与未来的设计 1.7.1 Web标准与Web 2.0 1.7.2 用户体验技术 1.7.3 用户体验设计的发展趋势 第2章 XHTML与CSS基础 2.1 XHTML基础 2.2 选择合适的DTD 2.3 选择合适的标签 2.4 给CSS留下接口 2.5 良好的...

    div+css网站标准(WEB标准)

    DIV+CSS布局已经成为现代网站设计的标准实践,它不仅解决了HTML表格布局存在的问题,还带来了诸多优势,如提高可维护性、增强语义性和提高访问速度等。随着技术的不断进步,未来的网站设计将会更加注重用户体验和...

    CSS+XHTML+JavaScript完全学习手册

    此外,手册可能还会涉及JavaScript的高级主题,如面向对象编程、闭包和Promise,为未来的JavaScript框架和库的学习打下坚实基础。 这本《CSS+XHTML+JavaScript完全学习手册》涵盖了Web前端开发的三个主要支柱,无论...

    27款DIV+CSS模板 后台管理页面设计

    9. **最佳实践**:这些模板通常遵循Web开发的最佳实践,例如使用语义化的HTML标签,优化性能的CSS编码,以及适当地使用CSS预处理器如Sass或Less等。 总的来说,"27款DIV+CSS模板 后台管理页面设计"提供了一个丰富的...

    我的学校网页期末作业(纯html+css实现)

    该项目是一系列面向大学生的期末网页设计作业示例,涉及的主题非常广泛,包括但不限于个人、美食、公司、学校、旅游、电商等多个领域。这些示例均采用了HTML5和CSS3技术来构建,部分示例还包含了JavaScript以实现更...

    CSS:面向初学者的惊人而简单CSS项目

    "面向初学者的惊人而简单CSS项目"是一个非常适合新手入门的学习资源,它通过实践性的项目帮助学习者快速理解并运用CSS。 1. **CSS基本概念** - **层叠性**:CSS中的“层叠”意味着多个样式规则可以应用于同一个...

    Pro CSS for High Traffic Websites.pdf

    5. **没有大型团队工作经验的开发者**:尽管本书主要面向大型项目的开发者,但所介绍的最佳实践同样适用于各种规模的网站。 #### 二、主要内容概述 本书共分为11章及4个附录,每一章节都围绕着高流量网站的CSS开发...

    一个简单的HTML网页 个人网站设计与实现 HTML+CSS+JavaScript自适应个人相册展示留言博客模板

    此外,由于项目中的模板具有广泛的适用性,它们也可以成为未来开发个人或商业网站的基础。随着互联网技术的发展,掌握这些技能的学生将在就业市场上具有更强的竞争力。 总之,通过这样的项目实践,学生不仅能够学到...

    数据库应用实践教学大纲

    其中理论教学占19个课时,上机实践占29个课时,具体章节包括数据库基础知识、HTML编程、JavaScript编程、Visual Basic.NET应用、C#数据库编程、CSS应用、ASP.NET实例等,每个章节都结合理论与实践进行教学。...

    web 技术基础 css 设计

    综上所述,"Web技术基础—CSS设计"课程不仅提供了全面的前端开发理论知识,还注重实际操作技能的培养,为学生未来的职业发展奠定了坚实的基础。通过系统的课程学习和实践训练,学生将能够熟练掌握前端开发的核心技术...

    HTML5+CSS3帮助文档

    HTML5和CSS3是现代网页开发的两大核心技术,它们共同为网页提供了丰富的表现力和强大的交互功能。HTML5是超文本标记语言(HyperText Markup ...通过深入研究和实践,开发者可以充分利用它们来创建出色的现代网页。

    Apress.Pro.CSS.for.High.Traffic.Websites

    - 提供了关于CSS标准的全面指南,包括历史背景、当前版本以及未来趋势。 - **附录2:无障碍性指南** - 详细介绍了如何遵循WCAG等无障碍性标准,以确保网站对所有人开放。 - **附录3:浏览器支持指南** - 解释了...

    html大学生网站开发实践作业:传统文化网页设计题材【绒花6页】HTML+CSS+JavaScript

    综上所述,此项目不仅涵盖了HTML、CSS和JavaScript的基础知识,还涉及到了网页设计的高级技巧,非常适合初学者学习和实践。通过这样的项目练习,学生可以掌握网页设计的基本流程和技术要点,为未来的职业发展打下...

    精通HTML+CSS设计模式_PDF文件

    2. **OOCSS(Object-Oriented CSS)**:面向对象的CSS,强调组件化和重用性,通过分离结构和表现,减少代码冗余。 3. **SMACSS(Scalable and Modular Architecture for CSS)**:适用于大型项目的CSS架构,包括...

    面向对象课程设计

    面向对象课程设计是一门着重培养学生使用面向对象的方法学进行软件开发的实践课程。报告样本通常包含多个章节,详细介绍了从系统分析、设计、实现到测试的整个开发过程。本知识点将对报告样本中提到的关键概念和面向...

    web前端期末大作业:HTML+CSS+JavaScript绿色的盆栽花店网站响应式模板 大学生鲜花网页设计

    该项目是一项面向大学生的Web前端期末大作业,主要目的是通过实际动手设计和开发一个完整的网站来加深学生对HTML、CSS以及JavaScript的理解与应用能力。本项目聚焦于创建一个“绿色盆栽花店”的响应式网站模板,不仅...

Global site tag (gtag.js) - Google Analytics